VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/valid.c@ 97642

Last change on this file since 97642 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

  • Property svn:eol-style set to native
File size: 191.6 KB
Line 
1/*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * daniel@veillard.com
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#include <string.h>
14
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18
19#include <libxml/xmlmemory.h>
20#include <libxml/hash.h>
21#include <libxml/uri.h>
22#include <libxml/valid.h>
23#include <libxml/parser.h>
24#include <libxml/parserInternals.h>
25#include <libxml/xmlerror.h>
26#include <libxml/list.h>
27#include <libxml/globals.h>
28
29static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
30 int create);
31/* #define DEBUG_VALID_ALGO */
32/* #define DEBUG_REGEXP_ALGO */
33
34#define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
39#ifdef LIBXML_VALID_ENABLED
40static int
41xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
42 const xmlChar *value);
43#endif
44/************************************************************************
45 * *
46 * Error handling routines *
47 * *
48 ************************************************************************/
49
50/**
51 * xmlVErrMemory:
52 * @ctxt: an XML validation parser context
53 * @extra: extra information
54 *
55 * Handle an out of memory error
56 */
57static void
58xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
59{
60 xmlGenericErrorFunc channel = NULL;
61 xmlParserCtxtPtr pctxt = NULL;
62 void *data = NULL;
63
64 if (ctxt != NULL) {
65 channel = ctxt->error;
66 data = ctxt->userData;
67 /* Use the special values to detect if it is part of a parsing
68 context */
69 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
70 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
71 long delta = (char *) ctxt - (char *) ctxt->userData;
72 if ((delta > 0) && (delta < 250))
73 pctxt = ctxt->userData;
74 }
75 }
76 if (extra)
77 __xmlRaiseError(NULL, channel, data,
78 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
79 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
80 "Memory allocation failed : %s\n", extra);
81 else
82 __xmlRaiseError(NULL, channel, data,
83 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
84 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
85 "Memory allocation failed\n");
86}
87
88/**
89 * xmlErrValid:
90 * @ctxt: an XML validation parser context
91 * @error: the error number
92 * @extra: extra information
93 *
94 * Handle a validation error
95 */
96static void LIBXML_ATTR_FORMAT(3,0)
97xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
98 const char *msg, const char *extra)
99{
100 xmlGenericErrorFunc channel = NULL;
101 xmlParserCtxtPtr pctxt = NULL;
102 void *data = NULL;
103
104 if (ctxt != NULL) {
105 channel = ctxt->error;
106 data = ctxt->userData;
107 /* Use the special values to detect if it is part of a parsing
108 context */
109 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
110 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
111 long delta = (char *) ctxt - (char *) ctxt->userData;
112 if ((delta > 0) && (delta < 250))
113 pctxt = ctxt->userData;
114 }
115 }
116 if (extra)
117 __xmlRaiseError(NULL, channel, data,
118 pctxt, NULL, XML_FROM_VALID, error,
119 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
120 msg, extra);
121 else
122 __xmlRaiseError(NULL, channel, data,
123 pctxt, NULL, XML_FROM_VALID, error,
124 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
125 "%s", msg);
126}
127
128#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
129/**
130 * xmlErrValidNode:
131 * @ctxt: an XML validation parser context
132 * @node: the node raising the error
133 * @error: the error number
134 * @str1: extra information
135 * @str2: extra information
136 * @str3: extra information
137 *
138 * Handle a validation error, provide contextual information
139 */
140static void LIBXML_ATTR_FORMAT(4,0)
141xmlErrValidNode(xmlValidCtxtPtr ctxt,
142 xmlNodePtr node, xmlParserErrors error,
143 const char *msg, const xmlChar * str1,
144 const xmlChar * str2, const xmlChar * str3)
145{
146 xmlStructuredErrorFunc schannel = NULL;
147 xmlGenericErrorFunc channel = NULL;
148 xmlParserCtxtPtr pctxt = NULL;
149 void *data = NULL;
150
151 if (ctxt != NULL) {
152 channel = ctxt->error;
153 data = ctxt->userData;
154 /* Use the special values to detect if it is part of a parsing
155 context */
156 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
157 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
158 long delta = (char *) ctxt - (char *) ctxt->userData;
159 if ((delta > 0) && (delta < 250))
160 pctxt = ctxt->userData;
161 }
162 }
163 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
164 XML_ERR_ERROR, NULL, 0,
165 (const char *) str1,
166 (const char *) str2,
167 (const char *) str3, 0, 0, msg, str1, str2, str3);
168}
169#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
170
171#ifdef LIBXML_VALID_ENABLED
172/**
173 * xmlErrValidNodeNr:
174 * @ctxt: an XML validation parser context
175 * @node: the node raising the error
176 * @error: the error number
177 * @str1: extra information
178 * @int2: extra information
179 * @str3: extra information
180 *
181 * Handle a validation error, provide contextual information
182 */
183static void LIBXML_ATTR_FORMAT(4,0)
184xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
185 xmlNodePtr node, xmlParserErrors error,
186 const char *msg, const xmlChar * str1,
187 int int2, const xmlChar * str3)
188{
189 xmlStructuredErrorFunc schannel = NULL;
190 xmlGenericErrorFunc channel = NULL;
191 xmlParserCtxtPtr pctxt = NULL;
192 void *data = NULL;
193
194 if (ctxt != NULL) {
195 channel = ctxt->error;
196 data = ctxt->userData;
197 /* Use the special values to detect if it is part of a parsing
198 context */
199 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
200 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
201 long delta = (char *) ctxt - (char *) ctxt->userData;
202 if ((delta > 0) && (delta < 250))
203 pctxt = ctxt->userData;
204 }
205 }
206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
207 XML_ERR_ERROR, NULL, 0,
208 (const char *) str1,
209 (const char *) str3,
210 NULL, int2, 0, msg, str1, int2, str3);
211}
212
213/**
214 * xmlErrValidWarning:
215 * @ctxt: an XML validation parser context
216 * @node: the node raising the error
217 * @error: the error number
218 * @str1: extra information
219 * @str2: extra information
220 * @str3: extra information
221 *
222 * Handle a validation error, provide contextual information
223 */
224static void LIBXML_ATTR_FORMAT(4,0)
225xmlErrValidWarning(xmlValidCtxtPtr ctxt,
226 xmlNodePtr node, xmlParserErrors error,
227 const char *msg, const xmlChar * str1,
228 const xmlChar * str2, const xmlChar * str3)
229{
230 xmlStructuredErrorFunc schannel = NULL;
231 xmlGenericErrorFunc channel = NULL;
232 xmlParserCtxtPtr pctxt = NULL;
233 void *data = NULL;
234
235 if (ctxt != NULL) {
236 channel = ctxt->warning;
237 data = ctxt->userData;
238 /* Use the special values to detect if it is part of a parsing
239 context */
240 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
241 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
242 long delta = (char *) ctxt - (char *) ctxt->userData;
243 if ((delta > 0) && (delta < 250))
244 pctxt = ctxt->userData;
245 }
246 }
247 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
248 XML_ERR_WARNING, NULL, 0,
249 (const char *) str1,
250 (const char *) str2,
251 (const char *) str3, 0, 0, msg, str1, str2, str3);
252}
253
254
255
256#ifdef LIBXML_REGEXP_ENABLED
257/*
258 * If regexp are enabled we can do continuous validation without the
259 * need of a tree to validate the content model. this is done in each
260 * callbacks.
261 * Each xmlValidState represent the validation state associated to the
262 * set of nodes currently open from the document root to the current element.
263 */
264
265
266typedef struct _xmlValidState {
267 xmlElementPtr elemDecl; /* pointer to the content model */
268 xmlNodePtr node; /* pointer to the current node */
269 xmlRegExecCtxtPtr exec; /* regexp runtime */
270} _xmlValidState;
271
272
273static int
274vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
275 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
276 ctxt->vstateMax = 10;
277 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
278 sizeof(ctxt->vstateTab[0]));
279 if (ctxt->vstateTab == NULL) {
280 xmlVErrMemory(ctxt, "malloc failed");
281 return(-1);
282 }
283 }
284
285 if (ctxt->vstateNr >= ctxt->vstateMax) {
286 xmlValidState *tmp;
287
288 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
289 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
290 if (tmp == NULL) {
291 xmlVErrMemory(ctxt, "realloc failed");
292 return(-1);
293 }
294 ctxt->vstateMax *= 2;
295 ctxt->vstateTab = tmp;
296 }
297 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
298 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
299 ctxt->vstateTab[ctxt->vstateNr].node = node;
300 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
301 if (elemDecl->contModel == NULL)
302 xmlValidBuildContentModel(ctxt, elemDecl);
303 if (elemDecl->contModel != NULL) {
304 ctxt->vstateTab[ctxt->vstateNr].exec =
305 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
306 } else {
307 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
308 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
309 XML_ERR_INTERNAL_ERROR,
310 "Failed to build content model regexp for %s\n",
311 node->name, NULL, NULL);
312 }
313 }
314 return(ctxt->vstateNr++);
315}
316
317static int
318vstateVPop(xmlValidCtxtPtr ctxt) {
319 xmlElementPtr elemDecl;
320
321 if (ctxt->vstateNr < 1) return(-1);
322 ctxt->vstateNr--;
323 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
324 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
325 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
326 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
327 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
328 }
329 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
330 if (ctxt->vstateNr >= 1)
331 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
332 else
333 ctxt->vstate = NULL;
334 return(ctxt->vstateNr);
335}
336
337#else /* not LIBXML_REGEXP_ENABLED */
338/*
339 * If regexp are not enabled, it uses a home made algorithm less
340 * complex and easier to
341 * debug/maintain than a generic NFA -> DFA state based algo. The
342 * only restriction is on the deepness of the tree limited by the
343 * size of the occurs bitfield
344 *
345 * this is the content of a saved state for rollbacks
346 */
347
348#define ROLLBACK_OR 0
349#define ROLLBACK_PARENT 1
350
351typedef struct _xmlValidState {
352 xmlElementContentPtr cont; /* pointer to the content model subtree */
353 xmlNodePtr node; /* pointer to the current node in the list */
354 long occurs;/* bitfield for multiple occurrences */
355 unsigned char depth; /* current depth in the overall tree */
356 unsigned char state; /* ROLLBACK_XXX */
357} _xmlValidState;
358
359#define MAX_RECURSE 25000
360#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361#define CONT ctxt->vstate->cont
362#define NODE ctxt->vstate->node
363#define DEPTH ctxt->vstate->depth
364#define OCCURS ctxt->vstate->occurs
365#define STATE ctxt->vstate->state
366
367#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
369
370#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
372
373static int
374vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
375 xmlNodePtr node, unsigned char depth, long occurs,
376 unsigned char state) {
377 int i = ctxt->vstateNr - 1;
378
379 if (ctxt->vstateNr > MAX_RECURSE) {
380 return(-1);
381 }
382 if (ctxt->vstateTab == NULL) {
383 ctxt->vstateMax = 8;
384 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
385 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
386 if (ctxt->vstateTab == NULL) {
387 xmlVErrMemory(ctxt, "malloc failed");
388 return(-1);
389 }
390 }
391 if (ctxt->vstateNr >= ctxt->vstateMax) {
392 xmlValidState *tmp;
393
394 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
395 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
396 if (tmp == NULL) {
397 xmlVErrMemory(ctxt, "malloc failed");
398 return(-1);
399 }
400 ctxt->vstateMax *= 2;
401 ctxt->vstateTab = tmp;
402 ctxt->vstate = &ctxt->vstateTab[0];
403 }
404 /*
405 * Don't push on the stack a state already here
406 */
407 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
408 (ctxt->vstateTab[i].node == node) &&
409 (ctxt->vstateTab[i].depth == depth) &&
410 (ctxt->vstateTab[i].occurs == occurs) &&
411 (ctxt->vstateTab[i].state == state))
412 return(ctxt->vstateNr);
413 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
414 ctxt->vstateTab[ctxt->vstateNr].node = node;
415 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
416 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
417 ctxt->vstateTab[ctxt->vstateNr].state = state;
418 return(ctxt->vstateNr++);
419}
420
421static int
422vstateVPop(xmlValidCtxtPtr ctxt) {
423 if (ctxt->vstateNr <= 1) return(-1);
424 ctxt->vstateNr--;
425 ctxt->vstate = &ctxt->vstateTab[0];
426 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
427 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
428 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
429 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
430 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
431 return(ctxt->vstateNr);
432}
433
434#endif /* LIBXML_REGEXP_ENABLED */
435
436static int
437nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
438{
439 if (ctxt->nodeMax <= 0) {
440 ctxt->nodeMax = 4;
441 ctxt->nodeTab =
442 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
443 sizeof(ctxt->nodeTab[0]));
444 if (ctxt->nodeTab == NULL) {
445 xmlVErrMemory(ctxt, "malloc failed");
446 ctxt->nodeMax = 0;
447 return (0);
448 }
449 }
450 if (ctxt->nodeNr >= ctxt->nodeMax) {
451 xmlNodePtr *tmp;
452 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
453 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
454 if (tmp == NULL) {
455 xmlVErrMemory(ctxt, "realloc failed");
456 return (0);
457 }
458 ctxt->nodeMax *= 2;
459 ctxt->nodeTab = tmp;
460 }
461 ctxt->nodeTab[ctxt->nodeNr] = value;
462 ctxt->node = value;
463 return (ctxt->nodeNr++);
464}
465static xmlNodePtr
466nodeVPop(xmlValidCtxtPtr ctxt)
467{
468 xmlNodePtr ret;
469
470 if (ctxt->nodeNr <= 0)
471 return (NULL);
472 ctxt->nodeNr--;
473 if (ctxt->nodeNr > 0)
474 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
475 else
476 ctxt->node = NULL;
477 ret = ctxt->nodeTab[ctxt->nodeNr];
478 ctxt->nodeTab[ctxt->nodeNr] = NULL;
479 return (ret);
480}
481
482#ifdef DEBUG_VALID_ALGO
483static void
484xmlValidPrintNode(xmlNodePtr cur) {
485 if (cur == NULL) {
486 xmlGenericError(xmlGenericErrorContext, "null");
487 return;
488 }
489 switch (cur->type) {
490 case XML_ELEMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
492 break;
493 case XML_TEXT_NODE:
494 xmlGenericError(xmlGenericErrorContext, "text ");
495 break;
496 case XML_CDATA_SECTION_NODE:
497 xmlGenericError(xmlGenericErrorContext, "cdata ");
498 break;
499 case XML_ENTITY_REF_NODE:
500 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
501 break;
502 case XML_PI_NODE:
503 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
504 break;
505 case XML_COMMENT_NODE:
506 xmlGenericError(xmlGenericErrorContext, "comment ");
507 break;
508 case XML_ATTRIBUTE_NODE:
509 xmlGenericError(xmlGenericErrorContext, "?attr? ");
510 break;
511 case XML_ENTITY_NODE:
512 xmlGenericError(xmlGenericErrorContext, "?ent? ");
513 break;
514 case XML_DOCUMENT_NODE:
515 xmlGenericError(xmlGenericErrorContext, "?doc? ");
516 break;
517 case XML_DOCUMENT_TYPE_NODE:
518 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
519 break;
520 case XML_DOCUMENT_FRAG_NODE:
521 xmlGenericError(xmlGenericErrorContext, "?frag? ");
522 break;
523 case XML_NOTATION_NODE:
524 xmlGenericError(xmlGenericErrorContext, "?nota? ");
525 break;
526 case XML_HTML_DOCUMENT_NODE:
527 xmlGenericError(xmlGenericErrorContext, "?html? ");
528 break;
529#ifdef LIBXML_DOCB_ENABLED
530 case XML_DOCB_DOCUMENT_NODE:
531 xmlGenericError(xmlGenericErrorContext, "?docb? ");
532 break;
533#endif
534 case XML_DTD_NODE:
535 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
536 break;
537 case XML_ELEMENT_DECL:
538 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
539 break;
540 case XML_ATTRIBUTE_DECL:
541 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
542 break;
543 case XML_ENTITY_DECL:
544 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
545 break;
546 case XML_NAMESPACE_DECL:
547 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
548 break;
549 case XML_XINCLUDE_START:
550 xmlGenericError(xmlGenericErrorContext, "incstart ");
551 break;
552 case XML_XINCLUDE_END:
553 xmlGenericError(xmlGenericErrorContext, "incend ");
554 break;
555 }
556}
557
558static void
559xmlValidPrintNodeList(xmlNodePtr cur) {
560 if (cur == NULL)
561 xmlGenericError(xmlGenericErrorContext, "null ");
562 while (cur != NULL) {
563 xmlValidPrintNode(cur);
564 cur = cur->next;
565 }
566}
567
568static void
569xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
570 char expr[5000];
571
572 expr[0] = 0;
573 xmlGenericError(xmlGenericErrorContext, "valid: ");
574 xmlValidPrintNodeList(cur);
575 xmlGenericError(xmlGenericErrorContext, "against ");
576 xmlSnprintfElementContent(expr, 5000, cont, 1);
577 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
578}
579
580static void
581xmlValidDebugState(xmlValidStatePtr state) {
582 xmlGenericError(xmlGenericErrorContext, "(");
583 if (state->cont == NULL)
584 xmlGenericError(xmlGenericErrorContext, "null,");
585 else
586 switch (state->cont->type) {
587 case XML_ELEMENT_CONTENT_PCDATA:
588 xmlGenericError(xmlGenericErrorContext, "pcdata,");
589 break;
590 case XML_ELEMENT_CONTENT_ELEMENT:
591 xmlGenericError(xmlGenericErrorContext, "%s,",
592 state->cont->name);
593 break;
594 case XML_ELEMENT_CONTENT_SEQ:
595 xmlGenericError(xmlGenericErrorContext, "seq,");
596 break;
597 case XML_ELEMENT_CONTENT_OR:
598 xmlGenericError(xmlGenericErrorContext, "or,");
599 break;
600 }
601 xmlValidPrintNode(state->node);
602 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
603 state->depth, state->occurs, state->state);
604}
605
606static void
607xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
608 int i, j;
609
610 xmlGenericError(xmlGenericErrorContext, "state: ");
611 xmlValidDebugState(ctxt->vstate);
612 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
613 ctxt->vstateNr - 1);
614 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
615 xmlValidDebugState(&ctxt->vstateTab[j]);
616 xmlGenericError(xmlGenericErrorContext, "\n");
617}
618
619/*****
620#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
621 *****/
622
623#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
624#define DEBUG_VALID_MSG(m) \
625 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
626
627#else
628#define DEBUG_VALID_STATE(n,c)
629#define DEBUG_VALID_MSG(m)
630#endif
631
632/* TODO: use hash table for accesses to elem and attribute definitions */
633
634
635#define CHECK_DTD \
636 if (doc == NULL) return(0); \
637 else if ((doc->intSubset == NULL) && \
638 (doc->extSubset == NULL)) return(0)
639
640#ifdef LIBXML_REGEXP_ENABLED
641
642/************************************************************************
643 * *
644 * Content model validation based on the regexps *
645 * *
646 ************************************************************************/
647
648/**
649 * xmlValidBuildAContentModel:
650 * @content: the content model
651 * @ctxt: the schema parser context
652 * @name: the element name whose content is being built
653 *
654 * Generate the automata sequence needed for that type
655 *
656 * Returns 1 if successful or 0 in case of error.
657 */
658static int
659xmlValidBuildAContentModel(xmlElementContentPtr content,
660 xmlValidCtxtPtr ctxt,
661 const xmlChar *name) {
662 if (content == NULL) {
663 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
664 "Found NULL content in content model of %s\n",
665 name, NULL, NULL);
666 return(0);
667 }
668 switch (content->type) {
669 case XML_ELEMENT_CONTENT_PCDATA:
670 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
671 "Found PCDATA in content model of %s\n",
672 name, NULL, NULL);
673 return(0);
674 break;
675 case XML_ELEMENT_CONTENT_ELEMENT: {
676 xmlAutomataStatePtr oldstate = ctxt->state;
677 xmlChar fn[50];
678 xmlChar *fullname;
679
680 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
681 if (fullname == NULL) {
682 xmlVErrMemory(ctxt, "Building content model");
683 return(0);
684 }
685
686 switch (content->ocur) {
687 case XML_ELEMENT_CONTENT_ONCE:
688 ctxt->state = xmlAutomataNewTransition(ctxt->am,
689 ctxt->state, NULL, fullname, NULL);
690 break;
691 case XML_ELEMENT_CONTENT_OPT:
692 ctxt->state = xmlAutomataNewTransition(ctxt->am,
693 ctxt->state, NULL, fullname, NULL);
694 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
695 break;
696 case XML_ELEMENT_CONTENT_PLUS:
697 ctxt->state = xmlAutomataNewTransition(ctxt->am,
698 ctxt->state, NULL, fullname, NULL);
699 xmlAutomataNewTransition(ctxt->am, ctxt->state,
700 ctxt->state, fullname, NULL);
701 break;
702 case XML_ELEMENT_CONTENT_MULT:
703 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
704 ctxt->state, NULL);
705 xmlAutomataNewTransition(ctxt->am,
706 ctxt->state, ctxt->state, fullname, NULL);
707 break;
708 }
709 if ((fullname != fn) && (fullname != content->name))
710 xmlFree(fullname);
711 break;
712 }
713 case XML_ELEMENT_CONTENT_SEQ: {
714 xmlAutomataStatePtr oldstate, oldend;
715 xmlElementContentOccur ocur;
716
717 /*
718 * Simply iterate over the content
719 */
720 oldstate = ctxt->state;
721 ocur = content->ocur;
722 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
723 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
724 oldstate = ctxt->state;
725 }
726 do {
727 xmlValidBuildAContentModel(content->c1, ctxt, name);
728 content = content->c2;
729 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
730 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
731 xmlValidBuildAContentModel(content, ctxt, name);
732 oldend = ctxt->state;
733 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
734 switch (ocur) {
735 case XML_ELEMENT_CONTENT_ONCE:
736 break;
737 case XML_ELEMENT_CONTENT_OPT:
738 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
739 break;
740 case XML_ELEMENT_CONTENT_MULT:
741 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
742 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
743 break;
744 case XML_ELEMENT_CONTENT_PLUS:
745 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
746 break;
747 }
748 break;
749 }
750 case XML_ELEMENT_CONTENT_OR: {
751 xmlAutomataStatePtr oldstate, oldend;
752 xmlElementContentOccur ocur;
753
754 ocur = content->ocur;
755 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
756 (ocur == XML_ELEMENT_CONTENT_MULT)) {
757 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
758 ctxt->state, NULL);
759 }
760 oldstate = ctxt->state;
761 oldend = xmlAutomataNewState(ctxt->am);
762
763 /*
764 * iterate over the subtypes and remerge the end with an
765 * epsilon transition
766 */
767 do {
768 ctxt->state = oldstate;
769 xmlValidBuildAContentModel(content->c1, ctxt, name);
770 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
771 content = content->c2;
772 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
773 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
774 ctxt->state = oldstate;
775 xmlValidBuildAContentModel(content, ctxt, name);
776 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
777 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
778 switch (ocur) {
779 case XML_ELEMENT_CONTENT_ONCE:
780 break;
781 case XML_ELEMENT_CONTENT_OPT:
782 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
783 break;
784 case XML_ELEMENT_CONTENT_MULT:
785 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
786 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
787 break;
788 case XML_ELEMENT_CONTENT_PLUS:
789 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
790 break;
791 }
792 break;
793 }
794 default:
795 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
796 "ContentModel broken for element %s\n",
797 (const char *) name);
798 return(0);
799 }
800 return(1);
801}
802/**
803 * xmlValidBuildContentModel:
804 * @ctxt: a validation context
805 * @elem: an element declaration node
806 *
807 * (Re)Build the automata associated to the content model of this
808 * element
809 *
810 * Returns 1 in case of success, 0 in case of error
811 */
812int
813xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
814
815 if ((ctxt == NULL) || (elem == NULL))
816 return(0);
817 if (elem->type != XML_ELEMENT_DECL)
818 return(0);
819 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
820 return(1);
821 /* TODO: should we rebuild in this case ? */
822 if (elem->contModel != NULL) {
823 if (!xmlRegexpIsDeterminist(elem->contModel)) {
824 ctxt->valid = 0;
825 return(0);
826 }
827 return(1);
828 }
829
830 ctxt->am = xmlNewAutomata();
831 if (ctxt->am == NULL) {
832 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
833 XML_ERR_INTERNAL_ERROR,
834 "Cannot create automata for element %s\n",
835 elem->name, NULL, NULL);
836 return(0);
837 }
838 ctxt->state = xmlAutomataGetInitState(ctxt->am);
839 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
840 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
841 elem->contModel = xmlAutomataCompile(ctxt->am);
842 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
843 char expr[5000];
844 expr[0] = 0;
845 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
846 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
847 XML_DTD_CONTENT_NOT_DETERMINIST,
848 "Content model of %s is not determinist: %s\n",
849 elem->name, BAD_CAST expr, NULL);
850#ifdef DEBUG_REGEXP_ALGO
851 xmlRegexpPrint(stderr, elem->contModel);
852#endif
853 ctxt->valid = 0;
854 ctxt->state = NULL;
855 xmlFreeAutomata(ctxt->am);
856 ctxt->am = NULL;
857 return(0);
858 }
859 ctxt->state = NULL;
860 xmlFreeAutomata(ctxt->am);
861 ctxt->am = NULL;
862 return(1);
863}
864
865#endif /* LIBXML_REGEXP_ENABLED */
866
867/****************************************************************
868 * *
869 * Util functions for data allocation/deallocation *
870 * *
871 ****************************************************************/
872
873/**
874 * xmlNewValidCtxt:
875 *
876 * Allocate a validation context structure.
877 *
878 * Returns NULL if not, otherwise the new validation context structure
879 */
880xmlValidCtxtPtr xmlNewValidCtxt(void) {
881 xmlValidCtxtPtr ret;
882
883 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
884 xmlVErrMemory(NULL, "malloc failed");
885 return (NULL);
886 }
887
888 (void) memset(ret, 0, sizeof (xmlValidCtxt));
889
890 return (ret);
891}
892
893/**
894 * xmlFreeValidCtxt:
895 * @cur: the validation context to free
896 *
897 * Free a validation context structure.
898 */
899void
900xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
901 if (cur->vstateTab != NULL)
902 xmlFree(cur->vstateTab);
903 if (cur->nodeTab != NULL)
904 xmlFree(cur->nodeTab);
905 xmlFree(cur);
906}
907
908#endif /* LIBXML_VALID_ENABLED */
909
910/**
911 * xmlNewDocElementContent:
912 * @doc: the document
913 * @name: the subelement name or NULL
914 * @type: the type of element content decl
915 *
916 * Allocate an element content structure for the document.
917 *
918 * Returns NULL if not, otherwise the new element content structure
919 */
920xmlElementContentPtr
921xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
922 xmlElementContentType type) {
923 xmlElementContentPtr ret;
924 xmlDictPtr dict = NULL;
925
926 if (doc != NULL)
927 dict = doc->dict;
928
929 switch(type) {
930 case XML_ELEMENT_CONTENT_ELEMENT:
931 if (name == NULL) {
932 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
933 "xmlNewElementContent : name == NULL !\n",
934 NULL);
935 }
936 break;
937 case XML_ELEMENT_CONTENT_PCDATA:
938 case XML_ELEMENT_CONTENT_SEQ:
939 case XML_ELEMENT_CONTENT_OR:
940 if (name != NULL) {
941 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
942 "xmlNewElementContent : name != NULL !\n",
943 NULL);
944 }
945 break;
946 default:
947 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
948 "Internal: ELEMENT content corrupted invalid type\n",
949 NULL);
950 return(NULL);
951 }
952 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
953 if (ret == NULL) {
954 xmlVErrMemory(NULL, "malloc failed");
955 return(NULL);
956 }
957 memset(ret, 0, sizeof(xmlElementContent));
958 ret->type = type;
959 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
960 if (name != NULL) {
961 int l;
962 const xmlChar *tmp;
963
964 tmp = xmlSplitQName3(name, &l);
965 if (tmp == NULL) {
966 if (dict == NULL)
967 ret->name = xmlStrdup(name);
968 else
969 ret->name = xmlDictLookup(dict, name, -1);
970 } else {
971 if (dict == NULL) {
972 ret->prefix = xmlStrndup(name, l);
973 ret->name = xmlStrdup(tmp);
974 } else {
975 ret->prefix = xmlDictLookup(dict, name, l);
976 ret->name = xmlDictLookup(dict, tmp, -1);
977 }
978 }
979 }
980 return(ret);
981}
982
983/**
984 * xmlNewElementContent:
985 * @name: the subelement name or NULL
986 * @type: the type of element content decl
987 *
988 * Allocate an element content structure.
989 * Deprecated in favor of xmlNewDocElementContent
990 *
991 * Returns NULL if not, otherwise the new element content structure
992 */
993xmlElementContentPtr
994xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
995 return(xmlNewDocElementContent(NULL, name, type));
996}
997
998/**
999 * xmlCopyDocElementContent:
1000 * @doc: the document owning the element declaration
1001 * @cur: An element content pointer.
1002 *
1003 * Build a copy of an element content description.
1004 *
1005 * Returns the new xmlElementContentPtr or NULL in case of error.
1006 */
1007xmlElementContentPtr
1008xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1009 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1010 xmlDictPtr dict = NULL;
1011
1012 if (cur == NULL) return(NULL);
1013
1014 if (doc != NULL)
1015 dict = doc->dict;
1016
1017 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1018 if (ret == NULL) {
1019 xmlVErrMemory(NULL, "malloc failed");
1020 return(NULL);
1021 }
1022 memset(ret, 0, sizeof(xmlElementContent));
1023 ret->type = cur->type;
1024 ret->ocur = cur->ocur;
1025 if (cur->name != NULL) {
1026 if (dict)
1027 ret->name = xmlDictLookup(dict, cur->name, -1);
1028 else
1029 ret->name = xmlStrdup(cur->name);
1030 }
1031
1032 if (cur->prefix != NULL) {
1033 if (dict)
1034 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1035 else
1036 ret->prefix = xmlStrdup(cur->prefix);
1037 }
1038 if (cur->c1 != NULL)
1039 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1040 if (ret->c1 != NULL)
1041 ret->c1->parent = ret;
1042 if (cur->c2 != NULL) {
1043 prev = ret;
1044 cur = cur->c2;
1045 while (cur != NULL) {
1046 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1047 if (tmp == NULL) {
1048 xmlVErrMemory(NULL, "malloc failed");
1049 return(ret);
1050 }
1051 memset(tmp, 0, sizeof(xmlElementContent));
1052 tmp->type = cur->type;
1053 tmp->ocur = cur->ocur;
1054 prev->c2 = tmp;
1055 tmp->parent = prev;
1056 if (cur->name != NULL) {
1057 if (dict)
1058 tmp->name = xmlDictLookup(dict, cur->name, -1);
1059 else
1060 tmp->name = xmlStrdup(cur->name);
1061 }
1062
1063 if (cur->prefix != NULL) {
1064 if (dict)
1065 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1066 else
1067 tmp->prefix = xmlStrdup(cur->prefix);
1068 }
1069 if (cur->c1 != NULL)
1070 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1071 if (tmp->c1 != NULL)
1072 tmp->c1->parent = ret;
1073 prev = tmp;
1074 cur = cur->c2;
1075 }
1076 }
1077 return(ret);
1078}
1079
1080/**
1081 * xmlCopyElementContent:
1082 * @cur: An element content pointer.
1083 *
1084 * Build a copy of an element content description.
1085 * Deprecated, use xmlCopyDocElementContent instead
1086 *
1087 * Returns the new xmlElementContentPtr or NULL in case of error.
1088 */
1089xmlElementContentPtr
1090xmlCopyElementContent(xmlElementContentPtr cur) {
1091 return(xmlCopyDocElementContent(NULL, cur));
1092}
1093
1094/**
1095 * xmlFreeDocElementContent:
1096 * @doc: the document owning the element declaration
1097 * @cur: the element content tree to free
1098 *
1099 * Free an element content structure. The whole subtree is removed.
1100 */
1101void
1102xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1103 xmlDictPtr dict = NULL;
1104 size_t depth = 0;
1105
1106 if (cur == NULL)
1107 return;
1108 if (doc != NULL)
1109 dict = doc->dict;
1110
1111 while (1) {
1112 xmlElementContentPtr parent;
1113
1114 while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
1115 cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
1116 depth += 1;
1117 }
1118
1119 switch (cur->type) {
1120 case XML_ELEMENT_CONTENT_PCDATA:
1121 case XML_ELEMENT_CONTENT_ELEMENT:
1122 case XML_ELEMENT_CONTENT_SEQ:
1123 case XML_ELEMENT_CONTENT_OR:
1124 break;
1125 default:
1126 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1127 "Internal: ELEMENT content corrupted invalid type\n",
1128 NULL);
1129 return;
1130 }
1131 if (dict) {
1132 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1133 xmlFree((xmlChar *) cur->name);
1134 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1135 xmlFree((xmlChar *) cur->prefix);
1136 } else {
1137 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1138 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1139 }
1140 parent = cur->parent;
1141 if ((depth == 0) || (parent == NULL)) {
1142 xmlFree(cur);
1143 break;
1144 }
1145 if (cur == parent->c1)
1146 parent->c1 = NULL;
1147 else
1148 parent->c2 = NULL;
1149 xmlFree(cur);
1150
1151 if (parent->c2 != NULL) {
1152 cur = parent->c2;
1153 } else {
1154 depth -= 1;
1155 cur = parent;
1156 }
1157 }
1158}
1159
1160/**
1161 * xmlFreeElementContent:
1162 * @cur: the element content tree to free
1163 *
1164 * Free an element content structure. The whole subtree is removed.
1165 * Deprecated, use xmlFreeDocElementContent instead
1166 */
1167void
1168xmlFreeElementContent(xmlElementContentPtr cur) {
1169 xmlFreeDocElementContent(NULL, cur);
1170}
1171
1172#ifdef LIBXML_OUTPUT_ENABLED
1173/**
1174 * xmlDumpElementOccur:
1175 * @buf: An XML buffer
1176 * @cur: An element table
1177 *
1178 * Dump the occurrence operator of an element.
1179 */
1180static void
1181xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
1182 switch (cur->ocur) {
1183 case XML_ELEMENT_CONTENT_ONCE:
1184 break;
1185 case XML_ELEMENT_CONTENT_OPT:
1186 xmlBufferWriteChar(buf, "?");
1187 break;
1188 case XML_ELEMENT_CONTENT_MULT:
1189 xmlBufferWriteChar(buf, "*");
1190 break;
1191 case XML_ELEMENT_CONTENT_PLUS:
1192 xmlBufferWriteChar(buf, "+");
1193 break;
1194 }
1195}
1196
1197/**
1198 * xmlDumpElementContent:
1199 * @buf: An XML buffer
1200 * @content: An element table
1201 *
1202 * This will dump the content of the element table as an XML DTD definition
1203 */
1204static void
1205xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
1206 xmlElementContentPtr cur;
1207
1208 if (content == NULL) return;
1209
1210 xmlBufferWriteChar(buf, "(");
1211 cur = content;
1212
1213 do {
1214 if (cur == NULL) return;
1215
1216 switch (cur->type) {
1217 case XML_ELEMENT_CONTENT_PCDATA:
1218 xmlBufferWriteChar(buf, "#PCDATA");
1219 break;
1220 case XML_ELEMENT_CONTENT_ELEMENT:
1221 if (cur->prefix != NULL) {
1222 xmlBufferWriteCHAR(buf, cur->prefix);
1223 xmlBufferWriteChar(buf, ":");
1224 }
1225 xmlBufferWriteCHAR(buf, cur->name);
1226 break;
1227 case XML_ELEMENT_CONTENT_SEQ:
1228 case XML_ELEMENT_CONTENT_OR:
1229 if ((cur != content) &&
1230 (cur->parent != NULL) &&
1231 ((cur->type != cur->parent->type) ||
1232 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1233 xmlBufferWriteChar(buf, "(");
1234 cur = cur->c1;
1235 continue;
1236 default:
1237 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1238 "Internal: ELEMENT cur corrupted invalid type\n",
1239 NULL);
1240 }
1241
1242 while (cur != content) {
1243 xmlElementContentPtr parent = cur->parent;
1244
1245 if (parent == NULL) return;
1246
1247 if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
1248 (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
1249 ((cur->type != parent->type) ||
1250 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1251 xmlBufferWriteChar(buf, ")");
1252 xmlDumpElementOccur(buf, cur);
1253
1254 if (cur == parent->c1) {
1255 if (parent->type == XML_ELEMENT_CONTENT_SEQ)
1256 xmlBufferWriteChar(buf, " , ");
1257 else if (parent->type == XML_ELEMENT_CONTENT_OR)
1258 xmlBufferWriteChar(buf, " | ");
1259
1260 cur = parent->c2;
1261 break;
1262 }
1263
1264 cur = parent;
1265 }
1266 } while (cur != content);
1267
1268 xmlBufferWriteChar(buf, ")");
1269 xmlDumpElementOccur(buf, content);
1270}
1271
1272/**
1273 * xmlSprintfElementContent:
1274 * @buf: an output buffer
1275 * @content: An element table
1276 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1277 *
1278 * Deprecated, unsafe, use xmlSnprintfElementContent
1279 */
1280void
1281xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1282 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1283 int englob ATTRIBUTE_UNUSED) {
1284}
1285#endif /* LIBXML_OUTPUT_ENABLED */
1286
1287/**
1288 * xmlSnprintfElementContent:
1289 * @buf: an output buffer
1290 * @size: the buffer size
1291 * @content: An element table
1292 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1293 *
1294 * This will dump the content of the element content definition
1295 * Intended just for the debug routine
1296 */
1297void
1298xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1299 int len;
1300
1301 if (content == NULL) return;
1302 len = strlen(buf);
1303 if (size - len < 50) {
1304 if ((size - len > 4) && (buf[len - 1] != '.'))
1305 strcat(buf, " ...");
1306 return;
1307 }
1308 if (englob) strcat(buf, "(");
1309 switch (content->type) {
1310 case XML_ELEMENT_CONTENT_PCDATA:
1311 strcat(buf, "#PCDATA");
1312 break;
1313 case XML_ELEMENT_CONTENT_ELEMENT: {
1314 int qnameLen = xmlStrlen(content->name);
1315
1316 if (content->prefix != NULL)
1317 qnameLen += xmlStrlen(content->prefix) + 1;
1318 if (size - len < qnameLen + 10) {
1319 strcat(buf, " ...");
1320 return;
1321 }
1322 if (content->prefix != NULL) {
1323 strcat(buf, (char *) content->prefix);
1324 strcat(buf, ":");
1325 }
1326 if (content->name != NULL)
1327 strcat(buf, (char *) content->name);
1328 break;
1329 }
1330 case XML_ELEMENT_CONTENT_SEQ:
1331 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1332 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1333 xmlSnprintfElementContent(buf, size, content->c1, 1);
1334 else
1335 xmlSnprintfElementContent(buf, size, content->c1, 0);
1336 len = strlen(buf);
1337 if (size - len < 50) {
1338 if ((size - len > 4) && (buf[len - 1] != '.'))
1339 strcat(buf, " ...");
1340 return;
1341 }
1342 strcat(buf, " , ");
1343 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1344 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1345 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1346 xmlSnprintfElementContent(buf, size, content->c2, 1);
1347 else
1348 xmlSnprintfElementContent(buf, size, content->c2, 0);
1349 break;
1350 case XML_ELEMENT_CONTENT_OR:
1351 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1352 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1353 xmlSnprintfElementContent(buf, size, content->c1, 1);
1354 else
1355 xmlSnprintfElementContent(buf, size, content->c1, 0);
1356 len = strlen(buf);
1357 if (size - len < 50) {
1358 if ((size - len > 4) && (buf[len - 1] != '.'))
1359 strcat(buf, " ...");
1360 return;
1361 }
1362 strcat(buf, " | ");
1363 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1364 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1365 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1366 xmlSnprintfElementContent(buf, size, content->c2, 1);
1367 else
1368 xmlSnprintfElementContent(buf, size, content->c2, 0);
1369 break;
1370 }
1371 if (size - strlen(buf) <= 2) return;
1372 if (englob)
1373 strcat(buf, ")");
1374 switch (content->ocur) {
1375 case XML_ELEMENT_CONTENT_ONCE:
1376 break;
1377 case XML_ELEMENT_CONTENT_OPT:
1378 strcat(buf, "?");
1379 break;
1380 case XML_ELEMENT_CONTENT_MULT:
1381 strcat(buf, "*");
1382 break;
1383 case XML_ELEMENT_CONTENT_PLUS:
1384 strcat(buf, "+");
1385 break;
1386 }
1387}
1388
1389/****************************************************************
1390 * *
1391 * Registration of DTD declarations *
1392 * *
1393 ****************************************************************/
1394
1395/**
1396 * xmlFreeElement:
1397 * @elem: An element
1398 *
1399 * Deallocate the memory used by an element definition
1400 */
1401static void
1402xmlFreeElement(xmlElementPtr elem) {
1403 if (elem == NULL) return;
1404 xmlUnlinkNode((xmlNodePtr) elem);
1405 xmlFreeDocElementContent(elem->doc, elem->content);
1406 if (elem->name != NULL)
1407 xmlFree((xmlChar *) elem->name);
1408 if (elem->prefix != NULL)
1409 xmlFree((xmlChar *) elem->prefix);
1410#ifdef LIBXML_REGEXP_ENABLED
1411 if (elem->contModel != NULL)
1412 xmlRegFreeRegexp(elem->contModel);
1413#endif
1414 xmlFree(elem);
1415}
1416
1417
1418/**
1419 * xmlAddElementDecl:
1420 * @ctxt: the validation context
1421 * @dtd: pointer to the DTD
1422 * @name: the entity name
1423 * @type: the element type
1424 * @content: the element content tree or NULL
1425 *
1426 * Register a new element declaration
1427 *
1428 * Returns NULL if not, otherwise the entity
1429 */
1430xmlElementPtr
1431xmlAddElementDecl(xmlValidCtxtPtr ctxt,
1432 xmlDtdPtr dtd, const xmlChar *name,
1433 xmlElementTypeVal type,
1434 xmlElementContentPtr content) {
1435 xmlElementPtr ret;
1436 xmlElementTablePtr table;
1437 xmlAttributePtr oldAttributes = NULL;
1438 xmlChar *ns, *uqname;
1439
1440 if (dtd == NULL) {
1441 return(NULL);
1442 }
1443 if (name == NULL) {
1444 return(NULL);
1445 }
1446
1447 switch (type) {
1448 case XML_ELEMENT_TYPE_EMPTY:
1449 if (content != NULL) {
1450 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1451 "xmlAddElementDecl: content != NULL for EMPTY\n",
1452 NULL);
1453 return(NULL);
1454 }
1455 break;
1456 case XML_ELEMENT_TYPE_ANY:
1457 if (content != NULL) {
1458 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1459 "xmlAddElementDecl: content != NULL for ANY\n",
1460 NULL);
1461 return(NULL);
1462 }
1463 break;
1464 case XML_ELEMENT_TYPE_MIXED:
1465 if (content == NULL) {
1466 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1467 "xmlAddElementDecl: content == NULL for MIXED\n",
1468 NULL);
1469 return(NULL);
1470 }
1471 break;
1472 case XML_ELEMENT_TYPE_ELEMENT:
1473 if (content == NULL) {
1474 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1475 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1476 NULL);
1477 return(NULL);
1478 }
1479 break;
1480 default:
1481 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1482 "Internal: ELEMENT decl corrupted invalid type\n",
1483 NULL);
1484 return(NULL);
1485 }
1486
1487 /*
1488 * check if name is a QName
1489 */
1490 uqname = xmlSplitQName2(name, &ns);
1491 if (uqname != NULL)
1492 name = uqname;
1493
1494 /*
1495 * Create the Element table if needed.
1496 */
1497 table = (xmlElementTablePtr) dtd->elements;
1498 if (table == NULL) {
1499 xmlDictPtr dict = NULL;
1500
1501 if (dtd->doc != NULL)
1502 dict = dtd->doc->dict;
1503 table = xmlHashCreateDict(0, dict);
1504 dtd->elements = (void *) table;
1505 }
1506 if (table == NULL) {
1507 xmlVErrMemory(ctxt,
1508 "xmlAddElementDecl: Table creation failed!\n");
1509 if (uqname != NULL)
1510 xmlFree(uqname);
1511 if (ns != NULL)
1512 xmlFree(ns);
1513 return(NULL);
1514 }
1515
1516 /*
1517 * lookup old attributes inserted on an undefined element in the
1518 * internal subset.
1519 */
1520 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1521 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1522 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1523 oldAttributes = ret->attributes;
1524 ret->attributes = NULL;
1525 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1526 xmlFreeElement(ret);
1527 }
1528 }
1529
1530 /*
1531 * The element may already be present if one of its attribute
1532 * was registered first
1533 */
1534 ret = xmlHashLookup2(table, name, ns);
1535 if (ret != NULL) {
1536 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1537#ifdef LIBXML_VALID_ENABLED
1538 /*
1539 * The element is already defined in this DTD.
1540 */
1541 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1542 "Redefinition of element %s\n",
1543 name, NULL, NULL);
1544#endif /* LIBXML_VALID_ENABLED */
1545 if (uqname != NULL)
1546 xmlFree(uqname);
1547 if (ns != NULL)
1548 xmlFree(ns);
1549 return(NULL);
1550 }
1551 if (ns != NULL) {
1552 xmlFree(ns);
1553 ns = NULL;
1554 }
1555 } else {
1556 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1557 if (ret == NULL) {
1558 xmlVErrMemory(ctxt, "malloc failed");
1559 if (uqname != NULL)
1560 xmlFree(uqname);
1561 if (ns != NULL)
1562 xmlFree(ns);
1563 return(NULL);
1564 }
1565 memset(ret, 0, sizeof(xmlElement));
1566 ret->type = XML_ELEMENT_DECL;
1567
1568 /*
1569 * fill the structure.
1570 */
1571 ret->name = xmlStrdup(name);
1572 if (ret->name == NULL) {
1573 xmlVErrMemory(ctxt, "malloc failed");
1574 if (uqname != NULL)
1575 xmlFree(uqname);
1576 if (ns != NULL)
1577 xmlFree(ns);
1578 xmlFree(ret);
1579 return(NULL);
1580 }
1581 ret->prefix = ns;
1582
1583 /*
1584 * Validity Check:
1585 * Insertion must not fail
1586 */
1587 if (xmlHashAddEntry2(table, name, ns, ret)) {
1588#ifdef LIBXML_VALID_ENABLED
1589 /*
1590 * The element is already defined in this DTD.
1591 */
1592 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1593 "Redefinition of element %s\n",
1594 name, NULL, NULL);
1595#endif /* LIBXML_VALID_ENABLED */
1596 xmlFreeElement(ret);
1597 if (uqname != NULL)
1598 xmlFree(uqname);
1599 return(NULL);
1600 }
1601 /*
1602 * For new element, may have attributes from earlier
1603 * definition in internal subset
1604 */
1605 ret->attributes = oldAttributes;
1606 }
1607
1608 /*
1609 * Finish to fill the structure.
1610 */
1611 ret->etype = type;
1612 /*
1613 * Avoid a stupid copy when called by the parser
1614 * and flag it by setting a special parent value
1615 * so the parser doesn't unallocate it.
1616 */
1617 if ((ctxt != NULL) &&
1618 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1619 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
1620 ret->content = content;
1621 if (content != NULL)
1622 content->parent = (xmlElementContentPtr) 1;
1623 } else {
1624 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1625 }
1626
1627 /*
1628 * Link it to the DTD
1629 */
1630 ret->parent = dtd;
1631 ret->doc = dtd->doc;
1632 if (dtd->last == NULL) {
1633 dtd->children = dtd->last = (xmlNodePtr) ret;
1634 } else {
1635 dtd->last->next = (xmlNodePtr) ret;
1636 ret->prev = dtd->last;
1637 dtd->last = (xmlNodePtr) ret;
1638 }
1639 if (uqname != NULL)
1640 xmlFree(uqname);
1641 return(ret);
1642}
1643
1644static void
1645xmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) {
1646 xmlFreeElement((xmlElementPtr) elem);
1647}
1648
1649/**
1650 * xmlFreeElementTable:
1651 * @table: An element table
1652 *
1653 * Deallocate the memory used by an element hash table.
1654 */
1655void
1656xmlFreeElementTable(xmlElementTablePtr table) {
1657 xmlHashFree(table, xmlFreeElementTableEntry);
1658}
1659
1660#ifdef LIBXML_TREE_ENABLED
1661/**
1662 * xmlCopyElement:
1663 * @elem: An element
1664 *
1665 * Build a copy of an element.
1666 *
1667 * Returns the new xmlElementPtr or NULL in case of error.
1668 */
1669static void *
1670xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1671 xmlElementPtr elem = (xmlElementPtr) payload;
1672 xmlElementPtr cur;
1673
1674 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1675 if (cur == NULL) {
1676 xmlVErrMemory(NULL, "malloc failed");
1677 return(NULL);
1678 }
1679 memset(cur, 0, sizeof(xmlElement));
1680 cur->type = XML_ELEMENT_DECL;
1681 cur->etype = elem->etype;
1682 if (elem->name != NULL)
1683 cur->name = xmlStrdup(elem->name);
1684 else
1685 cur->name = NULL;
1686 if (elem->prefix != NULL)
1687 cur->prefix = xmlStrdup(elem->prefix);
1688 else
1689 cur->prefix = NULL;
1690 cur->content = xmlCopyElementContent(elem->content);
1691 /* TODO : rebuild the attribute list on the copy */
1692 cur->attributes = NULL;
1693 return(cur);
1694}
1695
1696/**
1697 * xmlCopyElementTable:
1698 * @table: An element table
1699 *
1700 * Build a copy of an element table.
1701 *
1702 * Returns the new xmlElementTablePtr or NULL in case of error.
1703 */
1704xmlElementTablePtr
1705xmlCopyElementTable(xmlElementTablePtr table) {
1706 return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1707}
1708#endif /* LIBXML_TREE_ENABLED */
1709
1710#ifdef LIBXML_OUTPUT_ENABLED
1711/**
1712 * xmlDumpElementDecl:
1713 * @buf: the XML buffer output
1714 * @elem: An element table
1715 *
1716 * This will dump the content of the element declaration as an XML
1717 * DTD definition
1718 */
1719void
1720xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1721 if ((buf == NULL) || (elem == NULL))
1722 return;
1723 switch (elem->etype) {
1724 case XML_ELEMENT_TYPE_EMPTY:
1725 xmlBufferWriteChar(buf, "<!ELEMENT ");
1726 if (elem->prefix != NULL) {
1727 xmlBufferWriteCHAR(buf, elem->prefix);
1728 xmlBufferWriteChar(buf, ":");
1729 }
1730 xmlBufferWriteCHAR(buf, elem->name);
1731 xmlBufferWriteChar(buf, " EMPTY>\n");
1732 break;
1733 case XML_ELEMENT_TYPE_ANY:
1734 xmlBufferWriteChar(buf, "<!ELEMENT ");
1735 if (elem->prefix != NULL) {
1736 xmlBufferWriteCHAR(buf, elem->prefix);
1737 xmlBufferWriteChar(buf, ":");
1738 }
1739 xmlBufferWriteCHAR(buf, elem->name);
1740 xmlBufferWriteChar(buf, " ANY>\n");
1741 break;
1742 case XML_ELEMENT_TYPE_MIXED:
1743 xmlBufferWriteChar(buf, "<!ELEMENT ");
1744 if (elem->prefix != NULL) {
1745 xmlBufferWriteCHAR(buf, elem->prefix);
1746 xmlBufferWriteChar(buf, ":");
1747 }
1748 xmlBufferWriteCHAR(buf, elem->name);
1749 xmlBufferWriteChar(buf, " ");
1750 xmlDumpElementContent(buf, elem->content);
1751 xmlBufferWriteChar(buf, ">\n");
1752 break;
1753 case XML_ELEMENT_TYPE_ELEMENT:
1754 xmlBufferWriteChar(buf, "<!ELEMENT ");
1755 if (elem->prefix != NULL) {
1756 xmlBufferWriteCHAR(buf, elem->prefix);
1757 xmlBufferWriteChar(buf, ":");
1758 }
1759 xmlBufferWriteCHAR(buf, elem->name);
1760 xmlBufferWriteChar(buf, " ");
1761 xmlDumpElementContent(buf, elem->content);
1762 xmlBufferWriteChar(buf, ">\n");
1763 break;
1764 default:
1765 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1766 "Internal: ELEMENT struct corrupted invalid type\n",
1767 NULL);
1768 }
1769}
1770
1771/**
1772 * xmlDumpElementDeclScan:
1773 * @elem: An element table
1774 * @buf: the XML buffer output
1775 *
1776 * This routine is used by the hash scan function. It just reverses
1777 * the arguments.
1778 */
1779static void
1780xmlDumpElementDeclScan(void *elem, void *buf,
1781 const xmlChar *name ATTRIBUTE_UNUSED) {
1782 xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1783}
1784
1785/**
1786 * xmlDumpElementTable:
1787 * @buf: the XML buffer output
1788 * @table: An element table
1789 *
1790 * This will dump the content of the element table as an XML DTD definition
1791 */
1792void
1793xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1794 if ((buf == NULL) || (table == NULL))
1795 return;
1796 xmlHashScan(table, xmlDumpElementDeclScan, buf);
1797}
1798#endif /* LIBXML_OUTPUT_ENABLED */
1799
1800/**
1801 * xmlCreateEnumeration:
1802 * @name: the enumeration name or NULL
1803 *
1804 * create and initialize an enumeration attribute node.
1805 *
1806 * Returns the xmlEnumerationPtr just created or NULL in case
1807 * of error.
1808 */
1809xmlEnumerationPtr
1810xmlCreateEnumeration(const xmlChar *name) {
1811 xmlEnumerationPtr ret;
1812
1813 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1814 if (ret == NULL) {
1815 xmlVErrMemory(NULL, "malloc failed");
1816 return(NULL);
1817 }
1818 memset(ret, 0, sizeof(xmlEnumeration));
1819
1820 if (name != NULL)
1821 ret->name = xmlStrdup(name);
1822 return(ret);
1823}
1824
1825/**
1826 * xmlFreeEnumeration:
1827 * @cur: the tree to free.
1828 *
1829 * free an enumeration attribute node (recursive).
1830 */
1831void
1832xmlFreeEnumeration(xmlEnumerationPtr cur) {
1833 if (cur == NULL) return;
1834
1835 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1836
1837 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1838 xmlFree(cur);
1839}
1840
1841#ifdef LIBXML_TREE_ENABLED
1842/**
1843 * xmlCopyEnumeration:
1844 * @cur: the tree to copy.
1845 *
1846 * Copy an enumeration attribute node (recursive).
1847 *
1848 * Returns the xmlEnumerationPtr just created or NULL in case
1849 * of error.
1850 */
1851xmlEnumerationPtr
1852xmlCopyEnumeration(xmlEnumerationPtr cur) {
1853 xmlEnumerationPtr ret;
1854
1855 if (cur == NULL) return(NULL);
1856 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1857 if (ret == NULL) return(NULL);
1858
1859 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1860 else ret->next = NULL;
1861
1862 return(ret);
1863}
1864#endif /* LIBXML_TREE_ENABLED */
1865
1866#ifdef LIBXML_OUTPUT_ENABLED
1867/**
1868 * xmlDumpEnumeration:
1869 * @buf: the XML buffer output
1870 * @enum: An enumeration
1871 *
1872 * This will dump the content of the enumeration
1873 */
1874static void
1875xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1876 if ((buf == NULL) || (cur == NULL))
1877 return;
1878
1879 xmlBufferWriteCHAR(buf, cur->name);
1880 if (cur->next == NULL)
1881 xmlBufferWriteChar(buf, ")");
1882 else {
1883 xmlBufferWriteChar(buf, " | ");
1884 xmlDumpEnumeration(buf, cur->next);
1885 }
1886}
1887#endif /* LIBXML_OUTPUT_ENABLED */
1888
1889#ifdef LIBXML_VALID_ENABLED
1890/**
1891 * xmlScanIDAttributeDecl:
1892 * @ctxt: the validation context
1893 * @elem: the element name
1894 * @err: whether to raise errors here
1895 *
1896 * Verify that the element don't have too many ID attributes
1897 * declared.
1898 *
1899 * Returns the number of ID attributes found.
1900 */
1901static int
1902xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1903 xmlAttributePtr cur;
1904 int ret = 0;
1905
1906 if (elem == NULL) return(0);
1907 cur = elem->attributes;
1908 while (cur != NULL) {
1909 if (cur->atype == XML_ATTRIBUTE_ID) {
1910 ret ++;
1911 if ((ret > 1) && (err))
1912 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1913 "Element %s has too many ID attributes defined : %s\n",
1914 elem->name, cur->name, NULL);
1915 }
1916 cur = cur->nexth;
1917 }
1918 return(ret);
1919}
1920#endif /* LIBXML_VALID_ENABLED */
1921
1922/**
1923 * xmlFreeAttribute:
1924 * @elem: An attribute
1925 *
1926 * Deallocate the memory used by an attribute definition
1927 */
1928static void
1929xmlFreeAttribute(xmlAttributePtr attr) {
1930 xmlDictPtr dict;
1931
1932 if (attr == NULL) return;
1933 if (attr->doc != NULL)
1934 dict = attr->doc->dict;
1935 else
1936 dict = NULL;
1937 xmlUnlinkNode((xmlNodePtr) attr);
1938 if (attr->tree != NULL)
1939 xmlFreeEnumeration(attr->tree);
1940 if (dict) {
1941 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1942 xmlFree((xmlChar *) attr->elem);
1943 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1944 xmlFree((xmlChar *) attr->name);
1945 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1946 xmlFree((xmlChar *) attr->prefix);
1947 if ((attr->defaultValue != NULL) &&
1948 (!xmlDictOwns(dict, attr->defaultValue)))
1949 xmlFree((xmlChar *) attr->defaultValue);
1950 } else {
1951 if (attr->elem != NULL)
1952 xmlFree((xmlChar *) attr->elem);
1953 if (attr->name != NULL)
1954 xmlFree((xmlChar *) attr->name);
1955 if (attr->defaultValue != NULL)
1956 xmlFree((xmlChar *) attr->defaultValue);
1957 if (attr->prefix != NULL)
1958 xmlFree((xmlChar *) attr->prefix);
1959 }
1960 xmlFree(attr);
1961}
1962
1963
1964/**
1965 * xmlAddAttributeDecl:
1966 * @ctxt: the validation context
1967 * @dtd: pointer to the DTD
1968 * @elem: the element name
1969 * @name: the attribute name
1970 * @ns: the attribute namespace prefix
1971 * @type: the attribute type
1972 * @def: the attribute default type
1973 * @defaultValue: the attribute default value
1974 * @tree: if it's an enumeration, the associated list
1975 *
1976 * Register a new attribute declaration
1977 * Note that @tree becomes the ownership of the DTD
1978 *
1979 * Returns NULL if not new, otherwise the attribute decl
1980 */
1981xmlAttributePtr
1982xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
1983 xmlDtdPtr dtd, const xmlChar *elem,
1984 const xmlChar *name, const xmlChar *ns,
1985 xmlAttributeType type, xmlAttributeDefault def,
1986 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1987 xmlAttributePtr ret;
1988 xmlAttributeTablePtr table;
1989 xmlElementPtr elemDef;
1990 xmlDictPtr dict = NULL;
1991
1992 if (dtd == NULL) {
1993 xmlFreeEnumeration(tree);
1994 return(NULL);
1995 }
1996 if (name == NULL) {
1997 xmlFreeEnumeration(tree);
1998 return(NULL);
1999 }
2000 if (elem == NULL) {
2001 xmlFreeEnumeration(tree);
2002 return(NULL);
2003 }
2004 if (dtd->doc != NULL)
2005 dict = dtd->doc->dict;
2006
2007#ifdef LIBXML_VALID_ENABLED
2008 /*
2009 * Check the type and possibly the default value.
2010 */
2011 switch (type) {
2012 case XML_ATTRIBUTE_CDATA:
2013 break;
2014 case XML_ATTRIBUTE_ID:
2015 break;
2016 case XML_ATTRIBUTE_IDREF:
2017 break;
2018 case XML_ATTRIBUTE_IDREFS:
2019 break;
2020 case XML_ATTRIBUTE_ENTITY:
2021 break;
2022 case XML_ATTRIBUTE_ENTITIES:
2023 break;
2024 case XML_ATTRIBUTE_NMTOKEN:
2025 break;
2026 case XML_ATTRIBUTE_NMTOKENS:
2027 break;
2028 case XML_ATTRIBUTE_ENUMERATION:
2029 break;
2030 case XML_ATTRIBUTE_NOTATION:
2031 break;
2032 default:
2033 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2034 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2035 NULL);
2036 xmlFreeEnumeration(tree);
2037 return(NULL);
2038 }
2039 if ((defaultValue != NULL) &&
2040 (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
2041 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2042 "Attribute %s of %s: invalid default value\n",
2043 elem, name, defaultValue);
2044 defaultValue = NULL;
2045 if (ctxt != NULL)
2046 ctxt->valid = 0;
2047 }
2048#endif /* LIBXML_VALID_ENABLED */
2049
2050 /*
2051 * Check first that an attribute defined in the external subset wasn't
2052 * already defined in the internal subset
2053 */
2054 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2055 (dtd->doc->intSubset != NULL) &&
2056 (dtd->doc->intSubset->attributes != NULL)) {
2057 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2058 if (ret != NULL) {
2059 xmlFreeEnumeration(tree);
2060 return(NULL);
2061 }
2062 }
2063
2064 /*
2065 * Create the Attribute table if needed.
2066 */
2067 table = (xmlAttributeTablePtr) dtd->attributes;
2068 if (table == NULL) {
2069 table = xmlHashCreateDict(0, dict);
2070 dtd->attributes = (void *) table;
2071 }
2072 if (table == NULL) {
2073 xmlVErrMemory(ctxt,
2074 "xmlAddAttributeDecl: Table creation failed!\n");
2075 xmlFreeEnumeration(tree);
2076 return(NULL);
2077 }
2078
2079
2080 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2081 if (ret == NULL) {
2082 xmlVErrMemory(ctxt, "malloc failed");
2083 xmlFreeEnumeration(tree);
2084 return(NULL);
2085 }
2086 memset(ret, 0, sizeof(xmlAttribute));
2087 ret->type = XML_ATTRIBUTE_DECL;
2088
2089 /*
2090 * fill the structure.
2091 */
2092 ret->atype = type;
2093 /*
2094 * doc must be set before possible error causes call
2095 * to xmlFreeAttribute (because it's used to check on
2096 * dict use)
2097 */
2098 ret->doc = dtd->doc;
2099 if (dict) {
2100 ret->name = xmlDictLookup(dict, name, -1);
2101 ret->prefix = xmlDictLookup(dict, ns, -1);
2102 ret->elem = xmlDictLookup(dict, elem, -1);
2103 } else {
2104 ret->name = xmlStrdup(name);
2105 ret->prefix = xmlStrdup(ns);
2106 ret->elem = xmlStrdup(elem);
2107 }
2108 ret->def = def;
2109 ret->tree = tree;
2110 if (defaultValue != NULL) {
2111 if (dict)
2112 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2113 else
2114 ret->defaultValue = xmlStrdup(defaultValue);
2115 }
2116
2117 /*
2118 * Validity Check:
2119 * Search the DTD for previous declarations of the ATTLIST
2120 */
2121 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2122#ifdef LIBXML_VALID_ENABLED
2123 /*
2124 * The attribute is already defined in this DTD.
2125 */
2126 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2127 "Attribute %s of element %s: already defined\n",
2128 name, elem, NULL);
2129#endif /* LIBXML_VALID_ENABLED */
2130 xmlFreeAttribute(ret);
2131 return(NULL);
2132 }
2133
2134 /*
2135 * Validity Check:
2136 * Multiple ID per element
2137 */
2138 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2139 if (elemDef != NULL) {
2140
2141#ifdef LIBXML_VALID_ENABLED
2142 if ((type == XML_ATTRIBUTE_ID) &&
2143 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2144 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2145 "Element %s has too may ID attributes defined : %s\n",
2146 elem, name, NULL);
2147 if (ctxt != NULL)
2148 ctxt->valid = 0;
2149 }
2150#endif /* LIBXML_VALID_ENABLED */
2151
2152 /*
2153 * Insert namespace default def first they need to be
2154 * processed first.
2155 */
2156 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2157 ((ret->prefix != NULL &&
2158 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2159 ret->nexth = elemDef->attributes;
2160 elemDef->attributes = ret;
2161 } else {
2162 xmlAttributePtr tmp = elemDef->attributes;
2163
2164 while ((tmp != NULL) &&
2165 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2166 ((ret->prefix != NULL &&
2167 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2168 if (tmp->nexth == NULL)
2169 break;
2170 tmp = tmp->nexth;
2171 }
2172 if (tmp != NULL) {
2173 ret->nexth = tmp->nexth;
2174 tmp->nexth = ret;
2175 } else {
2176 ret->nexth = elemDef->attributes;
2177 elemDef->attributes = ret;
2178 }
2179 }
2180 }
2181
2182 /*
2183 * Link it to the DTD
2184 */
2185 ret->parent = dtd;
2186 if (dtd->last == NULL) {
2187 dtd->children = dtd->last = (xmlNodePtr) ret;
2188 } else {
2189 dtd->last->next = (xmlNodePtr) ret;
2190 ret->prev = dtd->last;
2191 dtd->last = (xmlNodePtr) ret;
2192 }
2193 return(ret);
2194}
2195
2196static void
2197xmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) {
2198 xmlFreeAttribute((xmlAttributePtr) attr);
2199}
2200
2201/**
2202 * xmlFreeAttributeTable:
2203 * @table: An attribute table
2204 *
2205 * Deallocate the memory used by an entities hash table.
2206 */
2207void
2208xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2209 xmlHashFree(table, xmlFreeAttributeTableEntry);
2210}
2211
2212#ifdef LIBXML_TREE_ENABLED
2213/**
2214 * xmlCopyAttribute:
2215 * @attr: An attribute
2216 *
2217 * Build a copy of an attribute.
2218 *
2219 * Returns the new xmlAttributePtr or NULL in case of error.
2220 */
2221static void *
2222xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2223 xmlAttributePtr attr = (xmlAttributePtr) payload;
2224 xmlAttributePtr cur;
2225
2226 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2227 if (cur == NULL) {
2228 xmlVErrMemory(NULL, "malloc failed");
2229 return(NULL);
2230 }
2231 memset(cur, 0, sizeof(xmlAttribute));
2232 cur->type = XML_ATTRIBUTE_DECL;
2233 cur->atype = attr->atype;
2234 cur->def = attr->def;
2235 cur->tree = xmlCopyEnumeration(attr->tree);
2236 if (attr->elem != NULL)
2237 cur->elem = xmlStrdup(attr->elem);
2238 if (attr->name != NULL)
2239 cur->name = xmlStrdup(attr->name);
2240 if (attr->prefix != NULL)
2241 cur->prefix = xmlStrdup(attr->prefix);
2242 if (attr->defaultValue != NULL)
2243 cur->defaultValue = xmlStrdup(attr->defaultValue);
2244 return(cur);
2245}
2246
2247/**
2248 * xmlCopyAttributeTable:
2249 * @table: An attribute table
2250 *
2251 * Build a copy of an attribute table.
2252 *
2253 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2254 */
2255xmlAttributeTablePtr
2256xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2257 return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2258}
2259#endif /* LIBXML_TREE_ENABLED */
2260
2261#ifdef LIBXML_OUTPUT_ENABLED
2262/**
2263 * xmlDumpAttributeDecl:
2264 * @buf: the XML buffer output
2265 * @attr: An attribute declaration
2266 *
2267 * This will dump the content of the attribute declaration as an XML
2268 * DTD definition
2269 */
2270void
2271xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2272 if ((buf == NULL) || (attr == NULL))
2273 return;
2274 xmlBufferWriteChar(buf, "<!ATTLIST ");
2275 xmlBufferWriteCHAR(buf, attr->elem);
2276 xmlBufferWriteChar(buf, " ");
2277 if (attr->prefix != NULL) {
2278 xmlBufferWriteCHAR(buf, attr->prefix);
2279 xmlBufferWriteChar(buf, ":");
2280 }
2281 xmlBufferWriteCHAR(buf, attr->name);
2282 switch (attr->atype) {
2283 case XML_ATTRIBUTE_CDATA:
2284 xmlBufferWriteChar(buf, " CDATA");
2285 break;
2286 case XML_ATTRIBUTE_ID:
2287 xmlBufferWriteChar(buf, " ID");
2288 break;
2289 case XML_ATTRIBUTE_IDREF:
2290 xmlBufferWriteChar(buf, " IDREF");
2291 break;
2292 case XML_ATTRIBUTE_IDREFS:
2293 xmlBufferWriteChar(buf, " IDREFS");
2294 break;
2295 case XML_ATTRIBUTE_ENTITY:
2296 xmlBufferWriteChar(buf, " ENTITY");
2297 break;
2298 case XML_ATTRIBUTE_ENTITIES:
2299 xmlBufferWriteChar(buf, " ENTITIES");
2300 break;
2301 case XML_ATTRIBUTE_NMTOKEN:
2302 xmlBufferWriteChar(buf, " NMTOKEN");
2303 break;
2304 case XML_ATTRIBUTE_NMTOKENS:
2305 xmlBufferWriteChar(buf, " NMTOKENS");
2306 break;
2307 case XML_ATTRIBUTE_ENUMERATION:
2308 xmlBufferWriteChar(buf, " (");
2309 xmlDumpEnumeration(buf, attr->tree);
2310 break;
2311 case XML_ATTRIBUTE_NOTATION:
2312 xmlBufferWriteChar(buf, " NOTATION (");
2313 xmlDumpEnumeration(buf, attr->tree);
2314 break;
2315 default:
2316 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2317 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2318 NULL);
2319 }
2320 switch (attr->def) {
2321 case XML_ATTRIBUTE_NONE:
2322 break;
2323 case XML_ATTRIBUTE_REQUIRED:
2324 xmlBufferWriteChar(buf, " #REQUIRED");
2325 break;
2326 case XML_ATTRIBUTE_IMPLIED:
2327 xmlBufferWriteChar(buf, " #IMPLIED");
2328 break;
2329 case XML_ATTRIBUTE_FIXED:
2330 xmlBufferWriteChar(buf, " #FIXED");
2331 break;
2332 default:
2333 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2334 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2335 NULL);
2336 }
2337 if (attr->defaultValue != NULL) {
2338 xmlBufferWriteChar(buf, " ");
2339 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2340 }
2341 xmlBufferWriteChar(buf, ">\n");
2342}
2343
2344/**
2345 * xmlDumpAttributeDeclScan:
2346 * @attr: An attribute declaration
2347 * @buf: the XML buffer output
2348 *
2349 * This is used with the hash scan function - just reverses arguments
2350 */
2351static void
2352xmlDumpAttributeDeclScan(void *attr, void *buf,
2353 const xmlChar *name ATTRIBUTE_UNUSED) {
2354 xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2355}
2356
2357/**
2358 * xmlDumpAttributeTable:
2359 * @buf: the XML buffer output
2360 * @table: An attribute table
2361 *
2362 * This will dump the content of the attribute table as an XML DTD definition
2363 */
2364void
2365xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2366 if ((buf == NULL) || (table == NULL))
2367 return;
2368 xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
2369}
2370#endif /* LIBXML_OUTPUT_ENABLED */
2371
2372/************************************************************************
2373 * *
2374 * NOTATIONs *
2375 * *
2376 ************************************************************************/
2377/**
2378 * xmlFreeNotation:
2379 * @not: A notation
2380 *
2381 * Deallocate the memory used by an notation definition
2382 */
2383static void
2384xmlFreeNotation(xmlNotationPtr nota) {
2385 if (nota == NULL) return;
2386 if (nota->name != NULL)
2387 xmlFree((xmlChar *) nota->name);
2388 if (nota->PublicID != NULL)
2389 xmlFree((xmlChar *) nota->PublicID);
2390 if (nota->SystemID != NULL)
2391 xmlFree((xmlChar *) nota->SystemID);
2392 xmlFree(nota);
2393}
2394
2395
2396/**
2397 * xmlAddNotationDecl:
2398 * @dtd: pointer to the DTD
2399 * @ctxt: the validation context
2400 * @name: the entity name
2401 * @PublicID: the public identifier or NULL
2402 * @SystemID: the system identifier or NULL
2403 *
2404 * Register a new notation declaration
2405 *
2406 * Returns NULL if not, otherwise the entity
2407 */
2408xmlNotationPtr
2409xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
2410 const xmlChar *name,
2411 const xmlChar *PublicID, const xmlChar *SystemID) {
2412 xmlNotationPtr ret;
2413 xmlNotationTablePtr table;
2414
2415 if (dtd == NULL) {
2416 return(NULL);
2417 }
2418 if (name == NULL) {
2419 return(NULL);
2420 }
2421 if ((PublicID == NULL) && (SystemID == NULL)) {
2422 return(NULL);
2423 }
2424
2425 /*
2426 * Create the Notation table if needed.
2427 */
2428 table = (xmlNotationTablePtr) dtd->notations;
2429 if (table == NULL) {
2430 xmlDictPtr dict = NULL;
2431 if (dtd->doc != NULL)
2432 dict = dtd->doc->dict;
2433
2434 dtd->notations = table = xmlHashCreateDict(0, dict);
2435 }
2436 if (table == NULL) {
2437 xmlVErrMemory(ctxt,
2438 "xmlAddNotationDecl: Table creation failed!\n");
2439 return(NULL);
2440 }
2441
2442 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2443 if (ret == NULL) {
2444 xmlVErrMemory(ctxt, "malloc failed");
2445 return(NULL);
2446 }
2447 memset(ret, 0, sizeof(xmlNotation));
2448
2449 /*
2450 * fill the structure.
2451 */
2452 ret->name = xmlStrdup(name);
2453 if (SystemID != NULL)
2454 ret->SystemID = xmlStrdup(SystemID);
2455 if (PublicID != NULL)
2456 ret->PublicID = xmlStrdup(PublicID);
2457
2458 /*
2459 * Validity Check:
2460 * Check the DTD for previous declarations of the ATTLIST
2461 */
2462 if (xmlHashAddEntry(table, name, ret)) {
2463#ifdef LIBXML_VALID_ENABLED
2464 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2465 "xmlAddNotationDecl: %s already defined\n",
2466 (const char *) name);
2467#endif /* LIBXML_VALID_ENABLED */
2468 xmlFreeNotation(ret);
2469 return(NULL);
2470 }
2471 return(ret);
2472}
2473
2474static void
2475xmlFreeNotationTableEntry(void *nota, const xmlChar *name ATTRIBUTE_UNUSED) {
2476 xmlFreeNotation((xmlNotationPtr) nota);
2477}
2478
2479/**
2480 * xmlFreeNotationTable:
2481 * @table: An notation table
2482 *
2483 * Deallocate the memory used by an entities hash table.
2484 */
2485void
2486xmlFreeNotationTable(xmlNotationTablePtr table) {
2487 xmlHashFree(table, xmlFreeNotationTableEntry);
2488}
2489
2490#ifdef LIBXML_TREE_ENABLED
2491/**
2492 * xmlCopyNotation:
2493 * @nota: A notation
2494 *
2495 * Build a copy of a notation.
2496 *
2497 * Returns the new xmlNotationPtr or NULL in case of error.
2498 */
2499static void *
2500xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2501 xmlNotationPtr nota = (xmlNotationPtr) payload;
2502 xmlNotationPtr cur;
2503
2504 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2505 if (cur == NULL) {
2506 xmlVErrMemory(NULL, "malloc failed");
2507 return(NULL);
2508 }
2509 if (nota->name != NULL)
2510 cur->name = xmlStrdup(nota->name);
2511 else
2512 cur->name = NULL;
2513 if (nota->PublicID != NULL)
2514 cur->PublicID = xmlStrdup(nota->PublicID);
2515 else
2516 cur->PublicID = NULL;
2517 if (nota->SystemID != NULL)
2518 cur->SystemID = xmlStrdup(nota->SystemID);
2519 else
2520 cur->SystemID = NULL;
2521 return(cur);
2522}
2523
2524/**
2525 * xmlCopyNotationTable:
2526 * @table: A notation table
2527 *
2528 * Build a copy of a notation table.
2529 *
2530 * Returns the new xmlNotationTablePtr or NULL in case of error.
2531 */
2532xmlNotationTablePtr
2533xmlCopyNotationTable(xmlNotationTablePtr table) {
2534 return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2535}
2536#endif /* LIBXML_TREE_ENABLED */
2537
2538#ifdef LIBXML_OUTPUT_ENABLED
2539/**
2540 * xmlDumpNotationDecl:
2541 * @buf: the XML buffer output
2542 * @nota: A notation declaration
2543 *
2544 * This will dump the content the notation declaration as an XML DTD definition
2545 */
2546void
2547xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2548 if ((buf == NULL) || (nota == NULL))
2549 return;
2550 xmlBufferWriteChar(buf, "<!NOTATION ");
2551 xmlBufferWriteCHAR(buf, nota->name);
2552 if (nota->PublicID != NULL) {
2553 xmlBufferWriteChar(buf, " PUBLIC ");
2554 xmlBufferWriteQuotedString(buf, nota->PublicID);
2555 if (nota->SystemID != NULL) {
2556 xmlBufferWriteChar(buf, " ");
2557 xmlBufferWriteQuotedString(buf, nota->SystemID);
2558 }
2559 } else {
2560 xmlBufferWriteChar(buf, " SYSTEM ");
2561 xmlBufferWriteQuotedString(buf, nota->SystemID);
2562 }
2563 xmlBufferWriteChar(buf, " >\n");
2564}
2565
2566/**
2567 * xmlDumpNotationDeclScan:
2568 * @nota: A notation declaration
2569 * @buf: the XML buffer output
2570 *
2571 * This is called with the hash scan function, and just reverses args
2572 */
2573static void
2574xmlDumpNotationDeclScan(void *nota, void *buf,
2575 const xmlChar *name ATTRIBUTE_UNUSED) {
2576 xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2577}
2578
2579/**
2580 * xmlDumpNotationTable:
2581 * @buf: the XML buffer output
2582 * @table: A notation table
2583 *
2584 * This will dump the content of the notation table as an XML DTD definition
2585 */
2586void
2587xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2588 if ((buf == NULL) || (table == NULL))
2589 return;
2590 xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2591}
2592#endif /* LIBXML_OUTPUT_ENABLED */
2593
2594/************************************************************************
2595 * *
2596 * IDs *
2597 * *
2598 ************************************************************************/
2599/**
2600 * DICT_FREE:
2601 * @str: a string
2602 *
2603 * Free a string if it is not owned by the "dict" dictionary in the
2604 * current scope
2605 */
2606#define DICT_FREE(str) \
2607 if ((str) && ((!dict) || \
2608 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2609 xmlFree((char *)(str));
2610
2611/**
2612 * xmlValidNormalizeString:
2613 * @str: a string
2614 *
2615 * Normalize a string in-place.
2616 */
2617static void
2618xmlValidNormalizeString(xmlChar *str) {
2619 xmlChar *dst;
2620 const xmlChar *src;
2621
2622 if (str == NULL)
2623 return;
2624 src = str;
2625 dst = str;
2626
2627 while (*src == 0x20) src++;
2628 while (*src != 0) {
2629 if (*src == 0x20) {
2630 while (*src == 0x20) src++;
2631 if (*src != 0)
2632 *dst++ = 0x20;
2633 } else {
2634 *dst++ = *src++;
2635 }
2636 }
2637 *dst = 0;
2638}
2639
2640static int
2641xmlIsStreaming(xmlValidCtxtPtr ctxt) {
2642 xmlParserCtxtPtr pctxt;
2643
2644 if (ctxt == NULL)
2645 return(0);
2646 /*
2647 * These magic values are also abused to detect whether we're validating
2648 * while parsing a document. In this case, userData points to the parser
2649 * context.
2650 */
2651 if ((ctxt->finishDtd != XML_CTXT_FINISH_DTD_0) &&
2652 (ctxt->finishDtd != XML_CTXT_FINISH_DTD_1))
2653 return(0);
2654 pctxt = ctxt->userData;
2655 return(pctxt->parseMode == XML_PARSE_READER);
2656}
2657
2658/**
2659 * xmlFreeID:
2660 * @not: A id
2661 *
2662 * Deallocate the memory used by an id definition
2663 */
2664static void
2665xmlFreeID(xmlIDPtr id) {
2666 xmlDictPtr dict = NULL;
2667
2668 if (id == NULL) return;
2669
2670 if (id->doc != NULL)
2671 dict = id->doc->dict;
2672
2673 if (id->value != NULL)
2674 DICT_FREE(id->value)
2675 if (id->name != NULL)
2676 DICT_FREE(id->name)
2677 xmlFree(id);
2678}
2679
2680
2681/**
2682 * xmlAddID:
2683 * @ctxt: the validation context
2684 * @doc: pointer to the document
2685 * @value: the value name
2686 * @attr: the attribute holding the ID
2687 *
2688 * Register a new id declaration
2689 *
2690 * Returns NULL if not, otherwise the new xmlIDPtr
2691 */
2692xmlIDPtr
2693xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2694 xmlAttrPtr attr) {
2695 xmlIDPtr ret;
2696 xmlIDTablePtr table;
2697
2698 if (doc == NULL) {
2699 return(NULL);
2700 }
2701 if ((value == NULL) || (value[0] == 0)) {
2702 return(NULL);
2703 }
2704 if (attr == NULL) {
2705 return(NULL);
2706 }
2707
2708 /*
2709 * Create the ID table if needed.
2710 */
2711 table = (xmlIDTablePtr) doc->ids;
2712 if (table == NULL) {
2713 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2714 }
2715 if (table == NULL) {
2716 xmlVErrMemory(ctxt,
2717 "xmlAddID: Table creation failed!\n");
2718 return(NULL);
2719 }
2720
2721 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2722 if (ret == NULL) {
2723 xmlVErrMemory(ctxt, "malloc failed");
2724 return(NULL);
2725 }
2726
2727 /*
2728 * fill the structure.
2729 */
2730 ret->value = xmlStrdup(value);
2731 ret->doc = doc;
2732 if (xmlIsStreaming(ctxt)) {
2733 /*
2734 * Operating in streaming mode, attr is gonna disappear
2735 */
2736 if (doc->dict != NULL)
2737 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2738 else
2739 ret->name = xmlStrdup(attr->name);
2740 ret->attr = NULL;
2741 } else {
2742 ret->attr = attr;
2743 ret->name = NULL;
2744 }
2745 ret->lineno = xmlGetLineNo(attr->parent);
2746
2747 if (xmlHashAddEntry(table, value, ret) < 0) {
2748#ifdef LIBXML_VALID_ENABLED
2749 /*
2750 * The id is already defined in this DTD.
2751 */
2752 if (ctxt != NULL) {
2753 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2754 "ID %s already defined\n", value, NULL, NULL);
2755 }
2756#endif /* LIBXML_VALID_ENABLED */
2757 xmlFreeID(ret);
2758 return(NULL);
2759 }
2760 if (attr != NULL)
2761 attr->atype = XML_ATTRIBUTE_ID;
2762 return(ret);
2763}
2764
2765static void
2766xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) {
2767 xmlFreeID((xmlIDPtr) id);
2768}
2769
2770/**
2771 * xmlFreeIDTable:
2772 * @table: An id table
2773 *
2774 * Deallocate the memory used by an ID hash table.
2775 */
2776void
2777xmlFreeIDTable(xmlIDTablePtr table) {
2778 xmlHashFree(table, xmlFreeIDTableEntry);
2779}
2780
2781/**
2782 * xmlIsID:
2783 * @doc: the document
2784 * @elem: the element carrying the attribute
2785 * @attr: the attribute
2786 *
2787 * Determine whether an attribute is of type ID. In case we have DTD(s)
2788 * then this is done if DTD loading has been requested. In the case
2789 * of HTML documents parsed with the HTML parser, then ID detection is
2790 * done systematically.
2791 *
2792 * Returns 0 or 1 depending on the lookup result
2793 */
2794int
2795xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2796 if ((attr == NULL) || (attr->name == NULL)) return(0);
2797 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2798 (!strcmp((char *) attr->name, "id")) &&
2799 (!strcmp((char *) attr->ns->prefix, "xml")))
2800 return(1);
2801 if (doc == NULL) return(0);
2802 if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2803 (doc->type != XML_HTML_DOCUMENT_NODE)) {
2804 return(0);
2805 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2806 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2807 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2808 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2809 return(1);
2810 return(0);
2811 } else if (elem == NULL) {
2812 return(0);
2813 } else {
2814 xmlAttributePtr attrDecl = NULL;
2815
2816 xmlChar felem[50], fattr[50];
2817 xmlChar *fullelemname, *fullattrname;
2818
2819 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2820 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2821 (xmlChar *)elem->name;
2822
2823 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2824 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2825 (xmlChar *)attr->name;
2826
2827 if (fullelemname != NULL && fullattrname != NULL) {
2828 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2829 fullattrname);
2830 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2831 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2832 fullattrname);
2833 }
2834
2835 if ((fullattrname != fattr) && (fullattrname != attr->name))
2836 xmlFree(fullattrname);
2837 if ((fullelemname != felem) && (fullelemname != elem->name))
2838 xmlFree(fullelemname);
2839
2840 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2841 return(1);
2842 }
2843 return(0);
2844}
2845
2846/**
2847 * xmlRemoveID:
2848 * @doc: the document
2849 * @attr: the attribute
2850 *
2851 * Remove the given attribute from the ID table maintained internally.
2852 *
2853 * Returns -1 if the lookup failed and 0 otherwise
2854 */
2855int
2856xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2857 xmlIDTablePtr table;
2858 xmlIDPtr id;
2859 xmlChar *ID;
2860
2861 if (doc == NULL) return(-1);
2862 if (attr == NULL) return(-1);
2863
2864 table = (xmlIDTablePtr) doc->ids;
2865 if (table == NULL)
2866 return(-1);
2867
2868 ID = xmlNodeListGetString(doc, attr->children, 1);
2869 if (ID == NULL)
2870 return(-1);
2871 xmlValidNormalizeString(ID);
2872
2873 id = xmlHashLookup(table, ID);
2874 if (id == NULL || id->attr != attr) {
2875 xmlFree(ID);
2876 return(-1);
2877 }
2878
2879 xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry);
2880 xmlFree(ID);
2881 attr->atype = 0;
2882 return(0);
2883}
2884
2885/**
2886 * xmlGetID:
2887 * @doc: pointer to the document
2888 * @ID: the ID value
2889 *
2890 * Search the attribute declaring the given ID
2891 *
2892 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2893 */
2894xmlAttrPtr
2895xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2896 xmlIDTablePtr table;
2897 xmlIDPtr id;
2898
2899 if (doc == NULL) {
2900 return(NULL);
2901 }
2902
2903 if (ID == NULL) {
2904 return(NULL);
2905 }
2906
2907 table = (xmlIDTablePtr) doc->ids;
2908 if (table == NULL)
2909 return(NULL);
2910
2911 id = xmlHashLookup(table, ID);
2912 if (id == NULL)
2913 return(NULL);
2914 if (id->attr == NULL) {
2915 /*
2916 * We are operating on a stream, return a well known reference
2917 * since the attribute node doesn't exist anymore
2918 */
2919 return((xmlAttrPtr) doc);
2920 }
2921 return(id->attr);
2922}
2923
2924/************************************************************************
2925 * *
2926 * Refs *
2927 * *
2928 ************************************************************************/
2929typedef struct xmlRemoveMemo_t
2930{
2931 xmlListPtr l;
2932 xmlAttrPtr ap;
2933} xmlRemoveMemo;
2934
2935typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2936
2937typedef struct xmlValidateMemo_t
2938{
2939 xmlValidCtxtPtr ctxt;
2940 const xmlChar *name;
2941} xmlValidateMemo;
2942
2943typedef xmlValidateMemo *xmlValidateMemoPtr;
2944
2945/**
2946 * xmlFreeRef:
2947 * @lk: A list link
2948 *
2949 * Deallocate the memory used by a ref definition
2950 */
2951static void
2952xmlFreeRef(xmlLinkPtr lk) {
2953 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2954 if (ref == NULL) return;
2955 if (ref->value != NULL)
2956 xmlFree((xmlChar *)ref->value);
2957 if (ref->name != NULL)
2958 xmlFree((xmlChar *)ref->name);
2959 xmlFree(ref);
2960}
2961
2962/**
2963 * xmlFreeRefTableEntry:
2964 * @list_ref: A list of references.
2965 *
2966 * Deallocate the memory used by a list of references
2967 */
2968static void
2969xmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2970 xmlListPtr list_ref = (xmlListPtr) payload;
2971 if (list_ref == NULL) return;
2972 xmlListDelete(list_ref);
2973}
2974
2975/**
2976 * xmlWalkRemoveRef:
2977 * @data: Contents of current link
2978 * @user: Value supplied by the user
2979 *
2980 * Returns 0 to abort the walk or 1 to continue
2981 */
2982static int
2983xmlWalkRemoveRef(const void *data, void *user)
2984{
2985 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2986 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2987 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2988
2989 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2990 xmlListRemoveFirst(ref_list, (void *)data);
2991 return 0;
2992 }
2993 return 1;
2994}
2995
2996/**
2997 * xmlDummyCompare
2998 * @data0: Value supplied by the user
2999 * @data1: Value supplied by the user
3000 *
3001 * Do nothing, return 0. Used to create unordered lists.
3002 */
3003static int
3004xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
3005 const void *data1 ATTRIBUTE_UNUSED)
3006{
3007 return (0);
3008}
3009
3010/**
3011 * xmlAddRef:
3012 * @ctxt: the validation context
3013 * @doc: pointer to the document
3014 * @value: the value name
3015 * @attr: the attribute holding the Ref
3016 *
3017 * Register a new ref declaration
3018 *
3019 * Returns NULL if not, otherwise the new xmlRefPtr
3020 */
3021xmlRefPtr
3022xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
3023 xmlAttrPtr attr) {
3024 xmlRefPtr ret;
3025 xmlRefTablePtr table;
3026 xmlListPtr ref_list;
3027
3028 if (doc == NULL) {
3029 return(NULL);
3030 }
3031 if (value == NULL) {
3032 return(NULL);
3033 }
3034 if (attr == NULL) {
3035 return(NULL);
3036 }
3037
3038 /*
3039 * Create the Ref table if needed.
3040 */
3041 table = (xmlRefTablePtr) doc->refs;
3042 if (table == NULL) {
3043 doc->refs = table = xmlHashCreateDict(0, doc->dict);
3044 }
3045 if (table == NULL) {
3046 xmlVErrMemory(ctxt,
3047 "xmlAddRef: Table creation failed!\n");
3048 return(NULL);
3049 }
3050
3051 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
3052 if (ret == NULL) {
3053 xmlVErrMemory(ctxt, "malloc failed");
3054 return(NULL);
3055 }
3056
3057 /*
3058 * fill the structure.
3059 */
3060 ret->value = xmlStrdup(value);
3061 if (xmlIsStreaming(ctxt)) {
3062 /*
3063 * Operating in streaming mode, attr is gonna disappear
3064 */
3065 ret->name = xmlStrdup(attr->name);
3066 ret->attr = NULL;
3067 } else {
3068 ret->name = NULL;
3069 ret->attr = attr;
3070 }
3071 ret->lineno = xmlGetLineNo(attr->parent);
3072
3073 /* To add a reference :-
3074 * References are maintained as a list of references,
3075 * Lookup the entry, if no entry create new nodelist
3076 * Add the owning node to the NodeList
3077 * Return the ref
3078 */
3079
3080 if (NULL == (ref_list = xmlHashLookup(table, value))) {
3081 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
3082 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3083 "xmlAddRef: Reference list creation failed!\n",
3084 NULL);
3085 goto failed;
3086 }
3087 if (xmlHashAddEntry(table, value, ref_list) < 0) {
3088 xmlListDelete(ref_list);
3089 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3090 "xmlAddRef: Reference list insertion failed!\n",
3091 NULL);
3092 goto failed;
3093 }
3094 }
3095 if (xmlListAppend(ref_list, ret) != 0) {
3096 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3097 "xmlAddRef: Reference list insertion failed!\n",
3098 NULL);
3099 goto failed;
3100 }
3101 return(ret);
3102failed:
3103 if (ret != NULL) {
3104 if (ret->value != NULL)
3105 xmlFree((char *)ret->value);
3106 if (ret->name != NULL)
3107 xmlFree((char *)ret->name);
3108 xmlFree(ret);
3109 }
3110 return(NULL);
3111}
3112
3113/**
3114 * xmlFreeRefTable:
3115 * @table: An ref table
3116 *
3117 * Deallocate the memory used by an Ref hash table.
3118 */
3119void
3120xmlFreeRefTable(xmlRefTablePtr table) {
3121 xmlHashFree(table, xmlFreeRefTableEntry);
3122}
3123
3124/**
3125 * xmlIsRef:
3126 * @doc: the document
3127 * @elem: the element carrying the attribute
3128 * @attr: the attribute
3129 *
3130 * Determine whether an attribute is of type Ref. In case we have DTD(s)
3131 * then this is simple, otherwise we use an heuristic: name Ref (upper
3132 * or lowercase).
3133 *
3134 * Returns 0 or 1 depending on the lookup result
3135 */
3136int
3137xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3138 if (attr == NULL)
3139 return(0);
3140 if (doc == NULL) {
3141 doc = attr->doc;
3142 if (doc == NULL) return(0);
3143 }
3144
3145 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3146 return(0);
3147 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3148 /* TODO @@@ */
3149 return(0);
3150 } else {
3151 xmlAttributePtr attrDecl;
3152
3153 if (elem == NULL) return(0);
3154 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3155 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3156 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3157 elem->name, attr->name);
3158
3159 if ((attrDecl != NULL) &&
3160 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3161 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3162 return(1);
3163 }
3164 return(0);
3165}
3166
3167/**
3168 * xmlRemoveRef:
3169 * @doc: the document
3170 * @attr: the attribute
3171 *
3172 * Remove the given attribute from the Ref table maintained internally.
3173 *
3174 * Returns -1 if the lookup failed and 0 otherwise
3175 */
3176int
3177xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
3178 xmlListPtr ref_list;
3179 xmlRefTablePtr table;
3180 xmlChar *ID;
3181 xmlRemoveMemo target;
3182
3183 if (doc == NULL) return(-1);
3184 if (attr == NULL) return(-1);
3185
3186 table = (xmlRefTablePtr) doc->refs;
3187 if (table == NULL)
3188 return(-1);
3189
3190 ID = xmlNodeListGetString(doc, attr->children, 1);
3191 if (ID == NULL)
3192 return(-1);
3193
3194 ref_list = xmlHashLookup(table, ID);
3195 if(ref_list == NULL) {
3196 xmlFree(ID);
3197 return (-1);
3198 }
3199
3200 /* At this point, ref_list refers to a list of references which
3201 * have the same key as the supplied attr. Our list of references
3202 * is ordered by reference address and we don't have that information
3203 * here to use when removing. We'll have to walk the list and
3204 * check for a matching attribute, when we find one stop the walk
3205 * and remove the entry.
3206 * The list is ordered by reference, so that means we don't have the
3207 * key. Passing the list and the reference to the walker means we
3208 * will have enough data to be able to remove the entry.
3209 */
3210 target.l = ref_list;
3211 target.ap = attr;
3212
3213 /* Remove the supplied attr from our list */
3214 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3215
3216 /*If the list is empty then remove the list entry in the hash */
3217 if (xmlListEmpty(ref_list))
3218 xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry);
3219 xmlFree(ID);
3220 return(0);
3221}
3222
3223/**
3224 * xmlGetRefs:
3225 * @doc: pointer to the document
3226 * @ID: the ID value
3227 *
3228 * Find the set of references for the supplied ID.
3229 *
3230 * Returns NULL if not found, otherwise node set for the ID.
3231 */
3232xmlListPtr
3233xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
3234 xmlRefTablePtr table;
3235
3236 if (doc == NULL) {
3237 return(NULL);
3238 }
3239
3240 if (ID == NULL) {
3241 return(NULL);
3242 }
3243
3244 table = (xmlRefTablePtr) doc->refs;
3245 if (table == NULL)
3246 return(NULL);
3247
3248 return (xmlHashLookup(table, ID));
3249}
3250
3251/************************************************************************
3252 * *
3253 * Routines for validity checking *
3254 * *
3255 ************************************************************************/
3256
3257/**
3258 * xmlGetDtdElementDesc:
3259 * @dtd: a pointer to the DtD to search
3260 * @name: the element name
3261 *
3262 * Search the DTD for the description of this element
3263 *
3264 * returns the xmlElementPtr if found or NULL
3265 */
3266
3267xmlElementPtr
3268xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3269 xmlElementTablePtr table;
3270 xmlElementPtr cur;
3271 xmlChar *uqname = NULL, *prefix = NULL;
3272
3273 if ((dtd == NULL) || (name == NULL)) return(NULL);
3274 if (dtd->elements == NULL)
3275 return(NULL);
3276 table = (xmlElementTablePtr) dtd->elements;
3277
3278 uqname = xmlSplitQName2(name, &prefix);
3279 if (uqname != NULL)
3280 name = uqname;
3281 cur = xmlHashLookup2(table, name, prefix);
3282 if (prefix != NULL) xmlFree(prefix);
3283 if (uqname != NULL) xmlFree(uqname);
3284 return(cur);
3285}
3286/**
3287 * xmlGetDtdElementDesc2:
3288 * @dtd: a pointer to the DtD to search
3289 * @name: the element name
3290 * @create: create an empty description if not found
3291 *
3292 * Search the DTD for the description of this element
3293 *
3294 * returns the xmlElementPtr if found or NULL
3295 */
3296
3297static xmlElementPtr
3298xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3299 xmlElementTablePtr table;
3300 xmlElementPtr cur;
3301 xmlChar *uqname = NULL, *prefix = NULL;
3302
3303 if (dtd == NULL) return(NULL);
3304 if (dtd->elements == NULL) {
3305 xmlDictPtr dict = NULL;
3306
3307 if (dtd->doc != NULL)
3308 dict = dtd->doc->dict;
3309
3310 if (!create)
3311 return(NULL);
3312 /*
3313 * Create the Element table if needed.
3314 */
3315 table = (xmlElementTablePtr) dtd->elements;
3316 if (table == NULL) {
3317 table = xmlHashCreateDict(0, dict);
3318 dtd->elements = (void *) table;
3319 }
3320 if (table == NULL) {
3321 xmlVErrMemory(NULL, "element table allocation failed");
3322 return(NULL);
3323 }
3324 }
3325 table = (xmlElementTablePtr) dtd->elements;
3326
3327 uqname = xmlSplitQName2(name, &prefix);
3328 if (uqname != NULL)
3329 name = uqname;
3330 cur = xmlHashLookup2(table, name, prefix);
3331 if ((cur == NULL) && (create)) {
3332 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3333 if (cur == NULL) {
3334 xmlVErrMemory(NULL, "malloc failed");
3335 return(NULL);
3336 }
3337 memset(cur, 0, sizeof(xmlElement));
3338 cur->type = XML_ELEMENT_DECL;
3339
3340 /*
3341 * fill the structure.
3342 */
3343 cur->name = xmlStrdup(name);
3344 cur->prefix = xmlStrdup(prefix);
3345 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3346
3347 xmlHashAddEntry2(table, name, prefix, cur);
3348 }
3349 if (prefix != NULL) xmlFree(prefix);
3350 if (uqname != NULL) xmlFree(uqname);
3351 return(cur);
3352}
3353
3354/**
3355 * xmlGetDtdQElementDesc:
3356 * @dtd: a pointer to the DtD to search
3357 * @name: the element name
3358 * @prefix: the element namespace prefix
3359 *
3360 * Search the DTD for the description of this element
3361 *
3362 * returns the xmlElementPtr if found or NULL
3363 */
3364
3365xmlElementPtr
3366xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3367 const xmlChar *prefix) {
3368 xmlElementTablePtr table;
3369
3370 if (dtd == NULL) return(NULL);
3371 if (dtd->elements == NULL) return(NULL);
3372 table = (xmlElementTablePtr) dtd->elements;
3373
3374 return(xmlHashLookup2(table, name, prefix));
3375}
3376
3377/**
3378 * xmlGetDtdAttrDesc:
3379 * @dtd: a pointer to the DtD to search
3380 * @elem: the element name
3381 * @name: the attribute name
3382 *
3383 * Search the DTD for the description of this attribute on
3384 * this element.
3385 *
3386 * returns the xmlAttributePtr if found or NULL
3387 */
3388
3389xmlAttributePtr
3390xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3391 xmlAttributeTablePtr table;
3392 xmlAttributePtr cur;
3393 xmlChar *uqname = NULL, *prefix = NULL;
3394
3395 if (dtd == NULL) return(NULL);
3396 if (dtd->attributes == NULL) return(NULL);
3397
3398 table = (xmlAttributeTablePtr) dtd->attributes;
3399 if (table == NULL)
3400 return(NULL);
3401
3402 uqname = xmlSplitQName2(name, &prefix);
3403
3404 if (uqname != NULL) {
3405 cur = xmlHashLookup3(table, uqname, prefix, elem);
3406 if (prefix != NULL) xmlFree(prefix);
3407 if (uqname != NULL) xmlFree(uqname);
3408 } else
3409 cur = xmlHashLookup3(table, name, NULL, elem);
3410 return(cur);
3411}
3412
3413/**
3414 * xmlGetDtdQAttrDesc:
3415 * @dtd: a pointer to the DtD to search
3416 * @elem: the element name
3417 * @name: the attribute name
3418 * @prefix: the attribute namespace prefix
3419 *
3420 * Search the DTD for the description of this qualified attribute on
3421 * this element.
3422 *
3423 * returns the xmlAttributePtr if found or NULL
3424 */
3425
3426xmlAttributePtr
3427xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3428 const xmlChar *prefix) {
3429 xmlAttributeTablePtr table;
3430
3431 if (dtd == NULL) return(NULL);
3432 if (dtd->attributes == NULL) return(NULL);
3433 table = (xmlAttributeTablePtr) dtd->attributes;
3434
3435 return(xmlHashLookup3(table, name, prefix, elem));
3436}
3437
3438/**
3439 * xmlGetDtdNotationDesc:
3440 * @dtd: a pointer to the DtD to search
3441 * @name: the notation name
3442 *
3443 * Search the DTD for the description of this notation
3444 *
3445 * returns the xmlNotationPtr if found or NULL
3446 */
3447
3448xmlNotationPtr
3449xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3450 xmlNotationTablePtr table;
3451
3452 if (dtd == NULL) return(NULL);
3453 if (dtd->notations == NULL) return(NULL);
3454 table = (xmlNotationTablePtr) dtd->notations;
3455
3456 return(xmlHashLookup(table, name));
3457}
3458
3459#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3460/**
3461 * xmlValidateNotationUse:
3462 * @ctxt: the validation context
3463 * @doc: the document
3464 * @notationName: the notation name to check
3465 *
3466 * Validate that the given name match a notation declaration.
3467 * - [ VC: Notation Declared ]
3468 *
3469 * returns 1 if valid or 0 otherwise
3470 */
3471
3472int
3473xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3474 const xmlChar *notationName) {
3475 xmlNotationPtr notaDecl;
3476 if ((doc == NULL) || (doc->intSubset == NULL) ||
3477 (notationName == NULL)) return(-1);
3478
3479 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3480 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3481 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3482
3483 if ((notaDecl == NULL) && (ctxt != NULL)) {
3484 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3485 "NOTATION %s is not declared\n",
3486 notationName, NULL, NULL);
3487 return(0);
3488 }
3489 return(1);
3490}
3491#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3492
3493/**
3494 * xmlIsMixedElement:
3495 * @doc: the document
3496 * @name: the element name
3497 *
3498 * Search in the DtDs whether an element accept Mixed content (or ANY)
3499 * basically if it is supposed to accept text childs
3500 *
3501 * returns 0 if no, 1 if yes, and -1 if no element description is available
3502 */
3503
3504int
3505xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3506 xmlElementPtr elemDecl;
3507
3508 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3509
3510 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3511 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3512 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3513 if (elemDecl == NULL) return(-1);
3514 switch (elemDecl->etype) {
3515 case XML_ELEMENT_TYPE_UNDEFINED:
3516 return(-1);
3517 case XML_ELEMENT_TYPE_ELEMENT:
3518 return(0);
3519 case XML_ELEMENT_TYPE_EMPTY:
3520 /*
3521 * return 1 for EMPTY since we want VC error to pop up
3522 * on <empty> </empty> for example
3523 */
3524 case XML_ELEMENT_TYPE_ANY:
3525 case XML_ELEMENT_TYPE_MIXED:
3526 return(1);
3527 }
3528 return(1);
3529}
3530
3531#ifdef LIBXML_VALID_ENABLED
3532
3533static int
3534xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3535 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3536 /*
3537 * Use the new checks of production [4] [4a] amd [5] of the
3538 * Update 5 of XML-1.0
3539 */
3540 if (((c >= 'a') && (c <= 'z')) ||
3541 ((c >= 'A') && (c <= 'Z')) ||
3542 (c == '_') || (c == ':') ||
3543 ((c >= 0xC0) && (c <= 0xD6)) ||
3544 ((c >= 0xD8) && (c <= 0xF6)) ||
3545 ((c >= 0xF8) && (c <= 0x2FF)) ||
3546 ((c >= 0x370) && (c <= 0x37D)) ||
3547 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3548 ((c >= 0x200C) && (c <= 0x200D)) ||
3549 ((c >= 0x2070) && (c <= 0x218F)) ||
3550 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3551 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3552 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3553 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3554 ((c >= 0x10000) && (c <= 0xEFFFF)))
3555 return(1);
3556 } else {
3557 if (IS_LETTER(c) || (c == '_') || (c == ':'))
3558 return(1);
3559 }
3560 return(0);
3561}
3562
3563static int
3564xmlIsDocNameChar(xmlDocPtr doc, int c) {
3565 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3566 /*
3567 * Use the new checks of production [4] [4a] amd [5] of the
3568 * Update 5 of XML-1.0
3569 */
3570 if (((c >= 'a') && (c <= 'z')) ||
3571 ((c >= 'A') && (c <= 'Z')) ||
3572 ((c >= '0') && (c <= '9')) || /* !start */
3573 (c == '_') || (c == ':') ||
3574 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3575 ((c >= 0xC0) && (c <= 0xD6)) ||
3576 ((c >= 0xD8) && (c <= 0xF6)) ||
3577 ((c >= 0xF8) && (c <= 0x2FF)) ||
3578 ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3579 ((c >= 0x370) && (c <= 0x37D)) ||
3580 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3581 ((c >= 0x200C) && (c <= 0x200D)) ||
3582 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3583 ((c >= 0x2070) && (c <= 0x218F)) ||
3584 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3585 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3586 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3587 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3588 ((c >= 0x10000) && (c <= 0xEFFFF)))
3589 return(1);
3590 } else {
3591 if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3592 (c == '.') || (c == '-') ||
3593 (c == '_') || (c == ':') ||
3594 (IS_COMBINING(c)) ||
3595 (IS_EXTENDER(c)))
3596 return(1);
3597 }
3598 return(0);
3599}
3600
3601/**
3602 * xmlValidateNameValue:
3603 * @doc: pointer to the document or NULL
3604 * @value: an Name value
3605 *
3606 * Validate that the given value match Name production
3607 *
3608 * returns 1 if valid or 0 otherwise
3609 */
3610
3611static int
3612xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3613 const xmlChar *cur;
3614 int val, len;
3615
3616 if (value == NULL) return(0);
3617 cur = value;
3618 val = xmlStringCurrentChar(NULL, cur, &len);
3619 cur += len;
3620 if (!xmlIsDocNameStartChar(doc, val))
3621 return(0);
3622
3623 val = xmlStringCurrentChar(NULL, cur, &len);
3624 cur += len;
3625 while (xmlIsDocNameChar(doc, val)) {
3626 val = xmlStringCurrentChar(NULL, cur, &len);
3627 cur += len;
3628 }
3629
3630 if (val != 0) return(0);
3631
3632 return(1);
3633}
3634
3635/**
3636 * xmlValidateNameValue:
3637 * @value: an Name value
3638 *
3639 * Validate that the given value match Name production
3640 *
3641 * returns 1 if valid or 0 otherwise
3642 */
3643
3644int
3645xmlValidateNameValue(const xmlChar *value) {
3646 return(xmlValidateNameValueInternal(NULL, value));
3647}
3648
3649/**
3650 * xmlValidateNamesValueInternal:
3651 * @doc: pointer to the document or NULL
3652 * @value: an Names value
3653 *
3654 * Validate that the given value match Names production
3655 *
3656 * returns 1 if valid or 0 otherwise
3657 */
3658
3659static int
3660xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3661 const xmlChar *cur;
3662 int val, len;
3663
3664 if (value == NULL) return(0);
3665 cur = value;
3666 val = xmlStringCurrentChar(NULL, cur, &len);
3667 cur += len;
3668
3669 if (!xmlIsDocNameStartChar(doc, val))
3670 return(0);
3671
3672 val = xmlStringCurrentChar(NULL, cur, &len);
3673 cur += len;
3674 while (xmlIsDocNameChar(doc, val)) {
3675 val = xmlStringCurrentChar(NULL, cur, &len);
3676 cur += len;
3677 }
3678
3679 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3680 while (val == 0x20) {
3681 while (val == 0x20) {
3682 val = xmlStringCurrentChar(NULL, cur, &len);
3683 cur += len;
3684 }
3685
3686 if (!xmlIsDocNameStartChar(doc, val))
3687 return(0);
3688
3689 val = xmlStringCurrentChar(NULL, cur, &len);
3690 cur += len;
3691
3692 while (xmlIsDocNameChar(doc, val)) {
3693 val = xmlStringCurrentChar(NULL, cur, &len);
3694 cur += len;
3695 }
3696 }
3697
3698 if (val != 0) return(0);
3699
3700 return(1);
3701}
3702
3703/**
3704 * xmlValidateNamesValue:
3705 * @value: an Names value
3706 *
3707 * Validate that the given value match Names production
3708 *
3709 * returns 1 if valid or 0 otherwise
3710 */
3711
3712int
3713xmlValidateNamesValue(const xmlChar *value) {
3714 return(xmlValidateNamesValueInternal(NULL, value));
3715}
3716
3717/**
3718 * xmlValidateNmtokenValueInternal:
3719 * @doc: pointer to the document or NULL
3720 * @value: an Nmtoken value
3721 *
3722 * Validate that the given value match Nmtoken production
3723 *
3724 * [ VC: Name Token ]
3725 *
3726 * returns 1 if valid or 0 otherwise
3727 */
3728
3729static int
3730xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3731 const xmlChar *cur;
3732 int val, len;
3733
3734 if (value == NULL) return(0);
3735 cur = value;
3736 val = xmlStringCurrentChar(NULL, cur, &len);
3737 cur += len;
3738
3739 if (!xmlIsDocNameChar(doc, val))
3740 return(0);
3741
3742 val = xmlStringCurrentChar(NULL, cur, &len);
3743 cur += len;
3744 while (xmlIsDocNameChar(doc, val)) {
3745 val = xmlStringCurrentChar(NULL, cur, &len);
3746 cur += len;
3747 }
3748
3749 if (val != 0) return(0);
3750
3751 return(1);
3752}
3753
3754/**
3755 * xmlValidateNmtokenValue:
3756 * @value: an Nmtoken value
3757 *
3758 * Validate that the given value match Nmtoken production
3759 *
3760 * [ VC: Name Token ]
3761 *
3762 * returns 1 if valid or 0 otherwise
3763 */
3764
3765int
3766xmlValidateNmtokenValue(const xmlChar *value) {
3767 return(xmlValidateNmtokenValueInternal(NULL, value));
3768}
3769
3770/**
3771 * xmlValidateNmtokensValueInternal:
3772 * @doc: pointer to the document or NULL
3773 * @value: an Nmtokens value
3774 *
3775 * Validate that the given value match Nmtokens production
3776 *
3777 * [ VC: Name Token ]
3778 *
3779 * returns 1 if valid or 0 otherwise
3780 */
3781
3782static int
3783xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3784 const xmlChar *cur;
3785 int val, len;
3786
3787 if (value == NULL) return(0);
3788 cur = value;
3789 val = xmlStringCurrentChar(NULL, cur, &len);
3790 cur += len;
3791
3792 while (IS_BLANK(val)) {
3793 val = xmlStringCurrentChar(NULL, cur, &len);
3794 cur += len;
3795 }
3796
3797 if (!xmlIsDocNameChar(doc, val))
3798 return(0);
3799
3800 while (xmlIsDocNameChar(doc, val)) {
3801 val = xmlStringCurrentChar(NULL, cur, &len);
3802 cur += len;
3803 }
3804
3805 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3806 while (val == 0x20) {
3807 while (val == 0x20) {
3808 val = xmlStringCurrentChar(NULL, cur, &len);
3809 cur += len;
3810 }
3811 if (val == 0) return(1);
3812
3813 if (!xmlIsDocNameChar(doc, val))
3814 return(0);
3815
3816 val = xmlStringCurrentChar(NULL, cur, &len);
3817 cur += len;
3818
3819 while (xmlIsDocNameChar(doc, val)) {
3820 val = xmlStringCurrentChar(NULL, cur, &len);
3821 cur += len;
3822 }
3823 }
3824
3825 if (val != 0) return(0);
3826
3827 return(1);
3828}
3829
3830/**
3831 * xmlValidateNmtokensValue:
3832 * @value: an Nmtokens value
3833 *
3834 * Validate that the given value match Nmtokens production
3835 *
3836 * [ VC: Name Token ]
3837 *
3838 * returns 1 if valid or 0 otherwise
3839 */
3840
3841int
3842xmlValidateNmtokensValue(const xmlChar *value) {
3843 return(xmlValidateNmtokensValueInternal(NULL, value));
3844}
3845
3846/**
3847 * xmlValidateNotationDecl:
3848 * @ctxt: the validation context
3849 * @doc: a document instance
3850 * @nota: a notation definition
3851 *
3852 * Try to validate a single notation definition
3853 * basically it does the following checks as described by the
3854 * XML-1.0 recommendation:
3855 * - it seems that no validity constraint exists on notation declarations
3856 * But this function get called anyway ...
3857 *
3858 * returns 1 if valid or 0 otherwise
3859 */
3860
3861int
3862xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3863 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3864 int ret = 1;
3865
3866 return(ret);
3867}
3868
3869/**
3870 * xmlValidateAttributeValueInternal:
3871 * @doc: the document
3872 * @type: an attribute type
3873 * @value: an attribute value
3874 *
3875 * Validate that the given attribute value match the proper production
3876 *
3877 * returns 1 if valid or 0 otherwise
3878 */
3879
3880static int
3881xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3882 const xmlChar *value) {
3883 switch (type) {
3884 case XML_ATTRIBUTE_ENTITIES:
3885 case XML_ATTRIBUTE_IDREFS:
3886 return(xmlValidateNamesValueInternal(doc, value));
3887 case XML_ATTRIBUTE_ENTITY:
3888 case XML_ATTRIBUTE_IDREF:
3889 case XML_ATTRIBUTE_ID:
3890 case XML_ATTRIBUTE_NOTATION:
3891 return(xmlValidateNameValueInternal(doc, value));
3892 case XML_ATTRIBUTE_NMTOKENS:
3893 case XML_ATTRIBUTE_ENUMERATION:
3894 return(xmlValidateNmtokensValueInternal(doc, value));
3895 case XML_ATTRIBUTE_NMTOKEN:
3896 return(xmlValidateNmtokenValueInternal(doc, value));
3897 case XML_ATTRIBUTE_CDATA:
3898 break;
3899 }
3900 return(1);
3901}
3902
3903/**
3904 * xmlValidateAttributeValue:
3905 * @type: an attribute type
3906 * @value: an attribute value
3907 *
3908 * Validate that the given attribute value match the proper production
3909 *
3910 * [ VC: ID ]
3911 * Values of type ID must match the Name production....
3912 *
3913 * [ VC: IDREF ]
3914 * Values of type IDREF must match the Name production, and values
3915 * of type IDREFS must match Names ...
3916 *
3917 * [ VC: Entity Name ]
3918 * Values of type ENTITY must match the Name production, values
3919 * of type ENTITIES must match Names ...
3920 *
3921 * [ VC: Name Token ]
3922 * Values of type NMTOKEN must match the Nmtoken production; values
3923 * of type NMTOKENS must match Nmtokens.
3924 *
3925 * returns 1 if valid or 0 otherwise
3926 */
3927int
3928xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3929 return(xmlValidateAttributeValueInternal(NULL, type, value));
3930}
3931
3932/**
3933 * xmlValidateAttributeValue2:
3934 * @ctxt: the validation context
3935 * @doc: the document
3936 * @name: the attribute name (used for error reporting only)
3937 * @type: the attribute type
3938 * @value: the attribute value
3939 *
3940 * Validate that the given attribute value match a given type.
3941 * This typically cannot be done before having finished parsing
3942 * the subsets.
3943 *
3944 * [ VC: IDREF ]
3945 * Values of type IDREF must match one of the declared IDs
3946 * Values of type IDREFS must match a sequence of the declared IDs
3947 * each Name must match the value of an ID attribute on some element
3948 * in the XML document; i.e. IDREF values must match the value of
3949 * some ID attribute
3950 *
3951 * [ VC: Entity Name ]
3952 * Values of type ENTITY must match one declared entity
3953 * Values of type ENTITIES must match a sequence of declared entities
3954 *
3955 * [ VC: Notation Attributes ]
3956 * all notation names in the declaration must be declared.
3957 *
3958 * returns 1 if valid or 0 otherwise
3959 */
3960
3961static int
3962xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3963 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3964 int ret = 1;
3965 switch (type) {
3966 case XML_ATTRIBUTE_IDREFS:
3967 case XML_ATTRIBUTE_IDREF:
3968 case XML_ATTRIBUTE_ID:
3969 case XML_ATTRIBUTE_NMTOKENS:
3970 case XML_ATTRIBUTE_ENUMERATION:
3971 case XML_ATTRIBUTE_NMTOKEN:
3972 case XML_ATTRIBUTE_CDATA:
3973 break;
3974 case XML_ATTRIBUTE_ENTITY: {
3975 xmlEntityPtr ent;
3976
3977 ent = xmlGetDocEntity(doc, value);
3978 /* yeah it's a bit messy... */
3979 if ((ent == NULL) && (doc->standalone == 1)) {
3980 doc->standalone = 0;
3981 ent = xmlGetDocEntity(doc, value);
3982 }
3983 if (ent == NULL) {
3984 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3985 XML_DTD_UNKNOWN_ENTITY,
3986 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3987 name, value, NULL);
3988 ret = 0;
3989 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3990 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3991 XML_DTD_ENTITY_TYPE,
3992 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3993 name, value, NULL);
3994 ret = 0;
3995 }
3996 break;
3997 }
3998 case XML_ATTRIBUTE_ENTITIES: {
3999 xmlChar *dup, *nam = NULL, *cur, save;
4000 xmlEntityPtr ent;
4001
4002 dup = xmlStrdup(value);
4003 if (dup == NULL)
4004 return(0);
4005 cur = dup;
4006 while (*cur != 0) {
4007 nam = cur;
4008 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
4009 save = *cur;
4010 *cur = 0;
4011 ent = xmlGetDocEntity(doc, nam);
4012 if (ent == NULL) {
4013 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4014 XML_DTD_UNKNOWN_ENTITY,
4015 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
4016 name, nam, NULL);
4017 ret = 0;
4018 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4019 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4020 XML_DTD_ENTITY_TYPE,
4021 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
4022 name, nam, NULL);
4023 ret = 0;
4024 }
4025 if (save == 0)
4026 break;
4027 *cur = save;
4028 while (IS_BLANK_CH(*cur)) cur++;
4029 }
4030 xmlFree(dup);
4031 break;
4032 }
4033 case XML_ATTRIBUTE_NOTATION: {
4034 xmlNotationPtr nota;
4035
4036 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4037 if ((nota == NULL) && (doc->extSubset != NULL))
4038 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4039
4040 if (nota == NULL) {
4041 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4042 XML_DTD_UNKNOWN_NOTATION,
4043 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
4044 name, value, NULL);
4045 ret = 0;
4046 }
4047 break;
4048 }
4049 }
4050 return(ret);
4051}
4052
4053/**
4054 * xmlValidCtxtNormalizeAttributeValue:
4055 * @ctxt: the validation context
4056 * @doc: the document
4057 * @elem: the parent
4058 * @name: the attribute name
4059 * @value: the attribute value
4060 * @ctxt: the validation context or NULL
4061 *
4062 * Does the validation related extra step of the normalization of attribute
4063 * values:
4064 *
4065 * If the declared value is not CDATA, then the XML processor must further
4066 * process the normalized attribute value by discarding any leading and
4067 * trailing space (#x20) characters, and by replacing sequences of space
4068 * (#x20) characters by single space (#x20) character.
4069 *
4070 * Also check VC: Standalone Document Declaration in P32, and update
4071 * ctxt->valid accordingly
4072 *
4073 * returns a new normalized string if normalization is needed, NULL otherwise
4074 * the caller must free the returned value.
4075 */
4076
4077xmlChar *
4078xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4079 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4080 xmlChar *ret;
4081 xmlAttributePtr attrDecl = NULL;
4082 int extsubset = 0;
4083
4084 if (doc == NULL) return(NULL);
4085 if (elem == NULL) return(NULL);
4086 if (name == NULL) return(NULL);
4087 if (value == NULL) return(NULL);
4088
4089 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4090 xmlChar fn[50];
4091 xmlChar *fullname;
4092
4093 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4094 if (fullname == NULL)
4095 return(NULL);
4096 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4097 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4098 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4099 if (attrDecl != NULL)
4100 extsubset = 1;
4101 }
4102 if ((fullname != fn) && (fullname != elem->name))
4103 xmlFree(fullname);
4104 }
4105 if ((attrDecl == NULL) && (doc->intSubset != NULL))
4106 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4107 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4108 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4109 if (attrDecl != NULL)
4110 extsubset = 1;
4111 }
4112
4113 if (attrDecl == NULL)
4114 return(NULL);
4115 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4116 return(NULL);
4117
4118 ret = xmlStrdup(value);
4119 if (ret == NULL)
4120 return(NULL);
4121 xmlValidNormalizeString(ret);
4122 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4123 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4124"standalone: %s on %s value had to be normalized based on external subset declaration\n",
4125 name, elem->name, NULL);
4126 ctxt->valid = 0;
4127 }
4128 return(ret);
4129}
4130
4131/**
4132 * xmlValidNormalizeAttributeValue:
4133 * @doc: the document
4134 * @elem: the parent
4135 * @name: the attribute name
4136 * @value: the attribute value
4137 *
4138 * Does the validation related extra step of the normalization of attribute
4139 * values:
4140 *
4141 * If the declared value is not CDATA, then the XML processor must further
4142 * process the normalized attribute value by discarding any leading and
4143 * trailing space (#x20) characters, and by replacing sequences of space
4144 * (#x20) characters by single space (#x20) character.
4145 *
4146 * Returns a new normalized string if normalization is needed, NULL otherwise
4147 * the caller must free the returned value.
4148 */
4149
4150xmlChar *
4151xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4152 const xmlChar *name, const xmlChar *value) {
4153 xmlChar *ret;
4154 xmlAttributePtr attrDecl = NULL;
4155
4156 if (doc == NULL) return(NULL);
4157 if (elem == NULL) return(NULL);
4158 if (name == NULL) return(NULL);
4159 if (value == NULL) return(NULL);
4160
4161 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4162 xmlChar fn[50];
4163 xmlChar *fullname;
4164
4165 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4166 if (fullname == NULL)
4167 return(NULL);
4168 if ((fullname != fn) && (fullname != elem->name))
4169 xmlFree(fullname);
4170 }
4171 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4172 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4173 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4174
4175 if (attrDecl == NULL)
4176 return(NULL);
4177 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4178 return(NULL);
4179
4180 ret = xmlStrdup(value);
4181 if (ret == NULL)
4182 return(NULL);
4183 xmlValidNormalizeString(ret);
4184 return(ret);
4185}
4186
4187static void
4188xmlValidateAttributeIdCallback(void *payload, void *data,
4189 const xmlChar *name ATTRIBUTE_UNUSED) {
4190 xmlAttributePtr attr = (xmlAttributePtr) payload;
4191 int *count = (int *) data;
4192 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4193}
4194
4195/**
4196 * xmlValidateAttributeDecl:
4197 * @ctxt: the validation context
4198 * @doc: a document instance
4199 * @attr: an attribute definition
4200 *
4201 * Try to validate a single attribute definition
4202 * basically it does the following checks as described by the
4203 * XML-1.0 recommendation:
4204 * - [ VC: Attribute Default Legal ]
4205 * - [ VC: Enumeration ]
4206 * - [ VC: ID Attribute Default ]
4207 *
4208 * The ID/IDREF uniqueness and matching are done separately
4209 *
4210 * returns 1 if valid or 0 otherwise
4211 */
4212
4213int
4214xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4215 xmlAttributePtr attr) {
4216 int ret = 1;
4217 int val;
4218 CHECK_DTD;
4219 if(attr == NULL) return(1);
4220
4221 /* Attribute Default Legal */
4222 /* Enumeration */
4223 if (attr->defaultValue != NULL) {
4224 val = xmlValidateAttributeValueInternal(doc, attr->atype,
4225 attr->defaultValue);
4226 if (val == 0) {
4227 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4228 "Syntax of default value for attribute %s of %s is not valid\n",
4229 attr->name, attr->elem, NULL);
4230 }
4231 ret &= val;
4232 }
4233
4234 /* ID Attribute Default */
4235 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4236 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4237 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4238 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4239 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4240 attr->name, attr->elem, NULL);
4241 ret = 0;
4242 }
4243
4244 /* One ID per Element Type */
4245 if (attr->atype == XML_ATTRIBUTE_ID) {
4246 int nbId;
4247
4248 /* the trick is that we parse DtD as their own internal subset */
4249 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4250 attr->elem);
4251 if (elem != NULL) {
4252 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4253 } else {
4254 xmlAttributeTablePtr table;
4255
4256 /*
4257 * The attribute may be declared in the internal subset and the
4258 * element in the external subset.
4259 */
4260 nbId = 0;
4261 if (doc->intSubset != NULL) {
4262 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4263 xmlHashScan3(table, NULL, NULL, attr->elem,
4264 xmlValidateAttributeIdCallback, &nbId);
4265 }
4266 }
4267 if (nbId > 1) {
4268
4269 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4270 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4271 attr->elem, nbId, attr->name);
4272 } else if (doc->extSubset != NULL) {
4273 int extId = 0;
4274 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4275 if (elem != NULL) {
4276 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4277 }
4278 if (extId > 1) {
4279 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4280 "Element %s has %d ID attribute defined in the external subset : %s\n",
4281 attr->elem, extId, attr->name);
4282 } else if (extId + nbId > 1) {
4283 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4284"Element %s has ID attributes defined in the internal and external subset : %s\n",
4285 attr->elem, attr->name, NULL);
4286 }
4287 }
4288 }
4289
4290 /* Validity Constraint: Enumeration */
4291 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4292 xmlEnumerationPtr tree = attr->tree;
4293 while (tree != NULL) {
4294 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4295 tree = tree->next;
4296 }
4297 if (tree == NULL) {
4298 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4299"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4300 attr->defaultValue, attr->name, attr->elem);
4301 ret = 0;
4302 }
4303 }
4304
4305 return(ret);
4306}
4307
4308/**
4309 * xmlValidateElementDecl:
4310 * @ctxt: the validation context
4311 * @doc: a document instance
4312 * @elem: an element definition
4313 *
4314 * Try to validate a single element definition
4315 * basically it does the following checks as described by the
4316 * XML-1.0 recommendation:
4317 * - [ VC: One ID per Element Type ]
4318 * - [ VC: No Duplicate Types ]
4319 * - [ VC: Unique Element Type Declaration ]
4320 *
4321 * returns 1 if valid or 0 otherwise
4322 */
4323
4324int
4325xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4326 xmlElementPtr elem) {
4327 int ret = 1;
4328 xmlElementPtr tst;
4329
4330 CHECK_DTD;
4331
4332 if (elem == NULL) return(1);
4333
4334#if 0
4335#ifdef LIBXML_REGEXP_ENABLED
4336 /* Build the regexp associated to the content model */
4337 ret = xmlValidBuildContentModel(ctxt, elem);
4338#endif
4339#endif
4340
4341 /* No Duplicate Types */
4342 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4343 xmlElementContentPtr cur, next;
4344 const xmlChar *name;
4345
4346 cur = elem->content;
4347 while (cur != NULL) {
4348 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4349 if (cur->c1 == NULL) break;
4350 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4351 name = cur->c1->name;
4352 next = cur->c2;
4353 while (next != NULL) {
4354 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4355 if ((xmlStrEqual(next->name, name)) &&
4356 (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4357 if (cur->c1->prefix == NULL) {
4358 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4359 "Definition of %s has duplicate references of %s\n",
4360 elem->name, name, NULL);
4361 } else {
4362 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4363 "Definition of %s has duplicate references of %s:%s\n",
4364 elem->name, cur->c1->prefix, name);
4365 }
4366 ret = 0;
4367 }
4368 break;
4369 }
4370 if (next->c1 == NULL) break;
4371 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4372 if ((xmlStrEqual(next->c1->name, name)) &&
4373 (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4374 if (cur->c1->prefix == NULL) {
4375 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4376 "Definition of %s has duplicate references to %s\n",
4377 elem->name, name, NULL);
4378 } else {
4379 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4380 "Definition of %s has duplicate references to %s:%s\n",
4381 elem->name, cur->c1->prefix, name);
4382 }
4383 ret = 0;
4384 }
4385 next = next->c2;
4386 }
4387 }
4388 cur = cur->c2;
4389 }
4390 }
4391
4392 /* VC: Unique Element Type Declaration */
4393 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4394 if ((tst != NULL ) && (tst != elem) &&
4395 ((tst->prefix == elem->prefix) ||
4396 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4397 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4398 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4399 "Redefinition of element %s\n",
4400 elem->name, NULL, NULL);
4401 ret = 0;
4402 }
4403 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4404 if ((tst != NULL ) && (tst != elem) &&
4405 ((tst->prefix == elem->prefix) ||
4406 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4407 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4408 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4409 "Redefinition of element %s\n",
4410 elem->name, NULL, NULL);
4411 ret = 0;
4412 }
4413 /* One ID per Element Type
4414 * already done when registering the attribute
4415 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4416 ret = 0;
4417 } */
4418 return(ret);
4419}
4420
4421/**
4422 * xmlValidateOneAttribute:
4423 * @ctxt: the validation context
4424 * @doc: a document instance
4425 * @elem: an element instance
4426 * @attr: an attribute instance
4427 * @value: the attribute value (without entities processing)
4428 *
4429 * Try to validate a single attribute for an element
4430 * basically it does the following checks as described by the
4431 * XML-1.0 recommendation:
4432 * - [ VC: Attribute Value Type ]
4433 * - [ VC: Fixed Attribute Default ]
4434 * - [ VC: Entity Name ]
4435 * - [ VC: Name Token ]
4436 * - [ VC: ID ]
4437 * - [ VC: IDREF ]
4438 * - [ VC: Entity Name ]
4439 * - [ VC: Notation Attributes ]
4440 *
4441 * The ID/IDREF uniqueness and matching are done separately
4442 *
4443 * returns 1 if valid or 0 otherwise
4444 */
4445
4446int
4447xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4448 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4449{
4450 xmlAttributePtr attrDecl = NULL;
4451 int val;
4452 int ret = 1;
4453
4454 CHECK_DTD;
4455 if ((elem == NULL) || (elem->name == NULL)) return(0);
4456 if ((attr == NULL) || (attr->name == NULL)) return(0);
4457
4458 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4459 xmlChar fn[50];
4460 xmlChar *fullname;
4461
4462 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4463 if (fullname == NULL)
4464 return(0);
4465 if (attr->ns != NULL) {
4466 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4467 attr->name, attr->ns->prefix);
4468 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4469 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4470 attr->name, attr->ns->prefix);
4471 } else {
4472 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4473 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4474 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4475 fullname, attr->name);
4476 }
4477 if ((fullname != fn) && (fullname != elem->name))
4478 xmlFree(fullname);
4479 }
4480 if (attrDecl == NULL) {
4481 if (attr->ns != NULL) {
4482 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4483 attr->name, attr->ns->prefix);
4484 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4485 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4486 attr->name, attr->ns->prefix);
4487 } else {
4488 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4489 elem->name, attr->name);
4490 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4491 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4492 elem->name, attr->name);
4493 }
4494 }
4495
4496
4497 /* Validity Constraint: Attribute Value Type */
4498 if (attrDecl == NULL) {
4499 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4500 "No declaration for attribute %s of element %s\n",
4501 attr->name, elem->name, NULL);
4502 return(0);
4503 }
4504 attr->atype = attrDecl->atype;
4505
4506 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4507 if (val == 0) {
4508 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4509 "Syntax of value for attribute %s of %s is not valid\n",
4510 attr->name, elem->name, NULL);
4511 ret = 0;
4512 }
4513
4514 /* Validity constraint: Fixed Attribute Default */
4515 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4516 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4517 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4518 "Value for attribute %s of %s is different from default \"%s\"\n",
4519 attr->name, elem->name, attrDecl->defaultValue);
4520 ret = 0;
4521 }
4522 }
4523
4524 /* Validity Constraint: ID uniqueness */
4525 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4526 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4527 ret = 0;
4528 }
4529
4530 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4531 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4532 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4533 ret = 0;
4534 }
4535
4536 /* Validity Constraint: Notation Attributes */
4537 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4538 xmlEnumerationPtr tree = attrDecl->tree;
4539 xmlNotationPtr nota;
4540
4541 /* First check that the given NOTATION was declared */
4542 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4543 if (nota == NULL)
4544 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4545
4546 if (nota == NULL) {
4547 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4548 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4549 value, attr->name, elem->name);
4550 ret = 0;
4551 }
4552
4553 /* Second, verify that it's among the list */
4554 while (tree != NULL) {
4555 if (xmlStrEqual(tree->name, value)) break;
4556 tree = tree->next;
4557 }
4558 if (tree == NULL) {
4559 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4560"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4561 value, attr->name, elem->name);
4562 ret = 0;
4563 }
4564 }
4565
4566 /* Validity Constraint: Enumeration */
4567 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4568 xmlEnumerationPtr tree = attrDecl->tree;
4569 while (tree != NULL) {
4570 if (xmlStrEqual(tree->name, value)) break;
4571 tree = tree->next;
4572 }
4573 if (tree == NULL) {
4574 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4575 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4576 value, attr->name, elem->name);
4577 ret = 0;
4578 }
4579 }
4580
4581 /* Fixed Attribute Default */
4582 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4583 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4584 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4585 "Value for attribute %s of %s must be \"%s\"\n",
4586 attr->name, elem->name, attrDecl->defaultValue);
4587 ret = 0;
4588 }
4589
4590 /* Extra check for the attribute value */
4591 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4592 attrDecl->atype, value);
4593
4594 return(ret);
4595}
4596
4597/**
4598 * xmlValidateOneNamespace:
4599 * @ctxt: the validation context
4600 * @doc: a document instance
4601 * @elem: an element instance
4602 * @prefix: the namespace prefix
4603 * @ns: an namespace declaration instance
4604 * @value: the attribute value (without entities processing)
4605 *
4606 * Try to validate a single namespace declaration for an element
4607 * basically it does the following checks as described by the
4608 * XML-1.0 recommendation:
4609 * - [ VC: Attribute Value Type ]
4610 * - [ VC: Fixed Attribute Default ]
4611 * - [ VC: Entity Name ]
4612 * - [ VC: Name Token ]
4613 * - [ VC: ID ]
4614 * - [ VC: IDREF ]
4615 * - [ VC: Entity Name ]
4616 * - [ VC: Notation Attributes ]
4617 *
4618 * The ID/IDREF uniqueness and matching are done separately
4619 *
4620 * returns 1 if valid or 0 otherwise
4621 */
4622
4623int
4624xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4625xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4626 /* xmlElementPtr elemDecl; */
4627 xmlAttributePtr attrDecl = NULL;
4628 int val;
4629 int ret = 1;
4630
4631 CHECK_DTD;
4632 if ((elem == NULL) || (elem->name == NULL)) return(0);
4633 if ((ns == NULL) || (ns->href == NULL)) return(0);
4634
4635 if (prefix != NULL) {
4636 xmlChar fn[50];
4637 xmlChar *fullname;
4638
4639 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4640 if (fullname == NULL) {
4641 xmlVErrMemory(ctxt, "Validating namespace");
4642 return(0);
4643 }
4644 if (ns->prefix != NULL) {
4645 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4646 ns->prefix, BAD_CAST "xmlns");
4647 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4648 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4649 ns->prefix, BAD_CAST "xmlns");
4650 } else {
4651 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4652 BAD_CAST "xmlns");
4653 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4654 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4655 BAD_CAST "xmlns");
4656 }
4657 if ((fullname != fn) && (fullname != elem->name))
4658 xmlFree(fullname);
4659 }
4660 if (attrDecl == NULL) {
4661 if (ns->prefix != NULL) {
4662 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4663 ns->prefix, BAD_CAST "xmlns");
4664 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4665 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4666 ns->prefix, BAD_CAST "xmlns");
4667 } else {
4668 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4669 elem->name, BAD_CAST "xmlns");
4670 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4671 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4672 elem->name, BAD_CAST "xmlns");
4673 }
4674 }
4675
4676
4677 /* Validity Constraint: Attribute Value Type */
4678 if (attrDecl == NULL) {
4679 if (ns->prefix != NULL) {
4680 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4681 "No declaration for attribute xmlns:%s of element %s\n",
4682 ns->prefix, elem->name, NULL);
4683 } else {
4684 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4685 "No declaration for attribute xmlns of element %s\n",
4686 elem->name, NULL, NULL);
4687 }
4688 return(0);
4689 }
4690
4691 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4692 if (val == 0) {
4693 if (ns->prefix != NULL) {
4694 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4695 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4696 ns->prefix, elem->name, NULL);
4697 } else {
4698 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4699 "Syntax of value for attribute xmlns of %s is not valid\n",
4700 elem->name, NULL, NULL);
4701 }
4702 ret = 0;
4703 }
4704
4705 /* Validity constraint: Fixed Attribute Default */
4706 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4707 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4708 if (ns->prefix != NULL) {
4709 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4710 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4711 ns->prefix, elem->name, attrDecl->defaultValue);
4712 } else {
4713 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4714 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4715 elem->name, attrDecl->defaultValue, NULL);
4716 }
4717 ret = 0;
4718 }
4719 }
4720
4721 /*
4722 * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4723 * xmlAddID and xmlAddRef for namespace declarations, but it makes
4724 * no practical sense to use ID types anyway.
4725 */
4726#if 0
4727 /* Validity Constraint: ID uniqueness */
4728 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4729 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4730 ret = 0;
4731 }
4732
4733 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4734 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4735 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4736 ret = 0;
4737 }
4738#endif
4739
4740 /* Validity Constraint: Notation Attributes */
4741 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4742 xmlEnumerationPtr tree = attrDecl->tree;
4743 xmlNotationPtr nota;
4744
4745 /* First check that the given NOTATION was declared */
4746 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4747 if (nota == NULL)
4748 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4749
4750 if (nota == NULL) {
4751 if (ns->prefix != NULL) {
4752 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4753 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4754 value, ns->prefix, elem->name);
4755 } else {
4756 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4757 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4758 value, elem->name, NULL);
4759 }
4760 ret = 0;
4761 }
4762
4763 /* Second, verify that it's among the list */
4764 while (tree != NULL) {
4765 if (xmlStrEqual(tree->name, value)) break;
4766 tree = tree->next;
4767 }
4768 if (tree == NULL) {
4769 if (ns->prefix != NULL) {
4770 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4771"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4772 value, ns->prefix, elem->name);
4773 } else {
4774 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4775"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4776 value, elem->name, NULL);
4777 }
4778 ret = 0;
4779 }
4780 }
4781
4782 /* Validity Constraint: Enumeration */
4783 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4784 xmlEnumerationPtr tree = attrDecl->tree;
4785 while (tree != NULL) {
4786 if (xmlStrEqual(tree->name, value)) break;
4787 tree = tree->next;
4788 }
4789 if (tree == NULL) {
4790 if (ns->prefix != NULL) {
4791 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4792"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4793 value, ns->prefix, elem->name);
4794 } else {
4795 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4796"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4797 value, elem->name, NULL);
4798 }
4799 ret = 0;
4800 }
4801 }
4802
4803 /* Fixed Attribute Default */
4804 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4805 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4806 if (ns->prefix != NULL) {
4807 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4808 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4809 ns->prefix, elem->name, attrDecl->defaultValue);
4810 } else {
4811 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4812 "Value for attribute xmlns of %s must be \"%s\"\n",
4813 elem->name, attrDecl->defaultValue, NULL);
4814 }
4815 ret = 0;
4816 }
4817
4818 /* Extra check for the attribute value */
4819 if (ns->prefix != NULL) {
4820 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4821 attrDecl->atype, value);
4822 } else {
4823 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4824 attrDecl->atype, value);
4825 }
4826
4827 return(ret);
4828}
4829
4830#ifndef LIBXML_REGEXP_ENABLED
4831/**
4832 * xmlValidateSkipIgnorable:
4833 * @ctxt: the validation context
4834 * @child: the child list
4835 *
4836 * Skip ignorable elements w.r.t. the validation process
4837 *
4838 * returns the first element to consider for validation of the content model
4839 */
4840
4841static xmlNodePtr
4842xmlValidateSkipIgnorable(xmlNodePtr child) {
4843 while (child != NULL) {
4844 switch (child->type) {
4845 /* These things are ignored (skipped) during validation. */
4846 case XML_PI_NODE:
4847 case XML_COMMENT_NODE:
4848 case XML_XINCLUDE_START:
4849 case XML_XINCLUDE_END:
4850 child = child->next;
4851 break;
4852 case XML_TEXT_NODE:
4853 if (xmlIsBlankNode(child))
4854 child = child->next;
4855 else
4856 return(child);
4857 break;
4858 /* keep current node */
4859 default:
4860 return(child);
4861 }
4862 }
4863 return(child);
4864}
4865
4866/**
4867 * xmlValidateElementType:
4868 * @ctxt: the validation context
4869 *
4870 * Try to validate the content model of an element internal function
4871 *
4872 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4873 * reference is found and -3 if the validation succeeded but
4874 * the content model is not determinist.
4875 */
4876
4877static int
4878xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4879 int ret = -1;
4880 int determinist = 1;
4881
4882 NODE = xmlValidateSkipIgnorable(NODE);
4883 if ((NODE == NULL) && (CONT == NULL))
4884 return(1);
4885 if ((NODE == NULL) &&
4886 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4887 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4888 return(1);
4889 }
4890 if (CONT == NULL) return(-1);
4891 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4892 return(-2);
4893
4894 /*
4895 * We arrive here when more states need to be examined
4896 */
4897cont:
4898
4899 /*
4900 * We just recovered from a rollback generated by a possible
4901 * epsilon transition, go directly to the analysis phase
4902 */
4903 if (STATE == ROLLBACK_PARENT) {
4904 DEBUG_VALID_MSG("restored parent branch");
4905 DEBUG_VALID_STATE(NODE, CONT)
4906 ret = 1;
4907 goto analyze;
4908 }
4909
4910 DEBUG_VALID_STATE(NODE, CONT)
4911 /*
4912 * we may have to save a backup state here. This is the equivalent
4913 * of handling epsilon transition in NFAs.
4914 */
4915 if ((CONT != NULL) &&
4916 ((CONT->parent == NULL) ||
4917 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4918 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4919 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4920 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4921 DEBUG_VALID_MSG("saving parent branch");
4922 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4923 return(0);
4924 }
4925
4926
4927 /*
4928 * Check first if the content matches
4929 */
4930 switch (CONT->type) {
4931 case XML_ELEMENT_CONTENT_PCDATA:
4932 if (NODE == NULL) {
4933 DEBUG_VALID_MSG("pcdata failed no node");
4934 ret = 0;
4935 break;
4936 }
4937 if (NODE->type == XML_TEXT_NODE) {
4938 DEBUG_VALID_MSG("pcdata found, skip to next");
4939 /*
4940 * go to next element in the content model
4941 * skipping ignorable elems
4942 */
4943 do {
4944 NODE = NODE->next;
4945 NODE = xmlValidateSkipIgnorable(NODE);
4946 if ((NODE != NULL) &&
4947 (NODE->type == XML_ENTITY_REF_NODE))
4948 return(-2);
4949 } while ((NODE != NULL) &&
4950 ((NODE->type != XML_ELEMENT_NODE) &&
4951 (NODE->type != XML_TEXT_NODE) &&
4952 (NODE->type != XML_CDATA_SECTION_NODE)));
4953 ret = 1;
4954 break;
4955 } else {
4956 DEBUG_VALID_MSG("pcdata failed");
4957 ret = 0;
4958 break;
4959 }
4960 break;
4961 case XML_ELEMENT_CONTENT_ELEMENT:
4962 if (NODE == NULL) {
4963 DEBUG_VALID_MSG("element failed no node");
4964 ret = 0;
4965 break;
4966 }
4967 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4968 (xmlStrEqual(NODE->name, CONT->name)));
4969 if (ret == 1) {
4970 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4971 ret = (CONT->prefix == NULL);
4972 } else if (CONT->prefix == NULL) {
4973 ret = 0;
4974 } else {
4975 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4976 }
4977 }
4978 if (ret == 1) {
4979 DEBUG_VALID_MSG("element found, skip to next");
4980 /*
4981 * go to next element in the content model
4982 * skipping ignorable elems
4983 */
4984 do {
4985 NODE = NODE->next;
4986 NODE = xmlValidateSkipIgnorable(NODE);
4987 if ((NODE != NULL) &&
4988 (NODE->type == XML_ENTITY_REF_NODE))
4989 return(-2);
4990 } while ((NODE != NULL) &&
4991 ((NODE->type != XML_ELEMENT_NODE) &&
4992 (NODE->type != XML_TEXT_NODE) &&
4993 (NODE->type != XML_CDATA_SECTION_NODE)));
4994 } else {
4995 DEBUG_VALID_MSG("element failed");
4996 ret = 0;
4997 break;
4998 }
4999 break;
5000 case XML_ELEMENT_CONTENT_OR:
5001 /*
5002 * Small optimization.
5003 */
5004 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
5005 if ((NODE == NULL) ||
5006 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
5007 DEPTH++;
5008 CONT = CONT->c2;
5009 goto cont;
5010 }
5011 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5012 ret = (CONT->c1->prefix == NULL);
5013 } else if (CONT->c1->prefix == NULL) {
5014 ret = 0;
5015 } else {
5016 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5017 }
5018 if (ret == 0) {
5019 DEPTH++;
5020 CONT = CONT->c2;
5021 goto cont;
5022 }
5023 }
5024
5025 /*
5026 * save the second branch 'or' branch
5027 */
5028 DEBUG_VALID_MSG("saving 'or' branch");
5029 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
5030 OCCURS, ROLLBACK_OR) < 0)
5031 return(-1);
5032 DEPTH++;
5033 CONT = CONT->c1;
5034 goto cont;
5035 case XML_ELEMENT_CONTENT_SEQ:
5036 /*
5037 * Small optimization.
5038 */
5039 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
5040 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
5041 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
5042 if ((NODE == NULL) ||
5043 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
5044 DEPTH++;
5045 CONT = CONT->c2;
5046 goto cont;
5047 }
5048 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5049 ret = (CONT->c1->prefix == NULL);
5050 } else if (CONT->c1->prefix == NULL) {
5051 ret = 0;
5052 } else {
5053 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5054 }
5055 if (ret == 0) {
5056 DEPTH++;
5057 CONT = CONT->c2;
5058 goto cont;
5059 }
5060 }
5061 DEPTH++;
5062 CONT = CONT->c1;
5063 goto cont;
5064 }
5065
5066 /*
5067 * At this point handle going up in the tree
5068 */
5069 if (ret == -1) {
5070 DEBUG_VALID_MSG("error found returning");
5071 return(ret);
5072 }
5073analyze:
5074 while (CONT != NULL) {
5075 /*
5076 * First do the analysis depending on the occurrence model at
5077 * this level.
5078 */
5079 if (ret == 0) {
5080 switch (CONT->ocur) {
5081 xmlNodePtr cur;
5082
5083 case XML_ELEMENT_CONTENT_ONCE:
5084 cur = ctxt->vstate->node;
5085 DEBUG_VALID_MSG("Once branch failed, rollback");
5086 if (vstateVPop(ctxt) < 0 ) {
5087 DEBUG_VALID_MSG("exhaustion, failed");
5088 return(0);
5089 }
5090 if (cur != ctxt->vstate->node)
5091 determinist = -3;
5092 goto cont;
5093 case XML_ELEMENT_CONTENT_PLUS:
5094 if (OCCURRENCE == 0) {
5095 cur = ctxt->vstate->node;
5096 DEBUG_VALID_MSG("Plus branch failed, rollback");
5097 if (vstateVPop(ctxt) < 0 ) {
5098 DEBUG_VALID_MSG("exhaustion, failed");
5099 return(0);
5100 }
5101 if (cur != ctxt->vstate->node)
5102 determinist = -3;
5103 goto cont;
5104 }
5105 DEBUG_VALID_MSG("Plus branch found");
5106 ret = 1;
5107 break;
5108 case XML_ELEMENT_CONTENT_MULT:
5109#ifdef DEBUG_VALID_ALGO
5110 if (OCCURRENCE == 0) {
5111 DEBUG_VALID_MSG("Mult branch failed");
5112 } else {
5113 DEBUG_VALID_MSG("Mult branch found");
5114 }
5115#endif
5116 ret = 1;
5117 break;
5118 case XML_ELEMENT_CONTENT_OPT:
5119 DEBUG_VALID_MSG("Option branch failed");
5120 ret = 1;
5121 break;
5122 }
5123 } else {
5124 switch (CONT->ocur) {
5125 case XML_ELEMENT_CONTENT_OPT:
5126 DEBUG_VALID_MSG("Option branch succeeded");
5127 ret = 1;
5128 break;
5129 case XML_ELEMENT_CONTENT_ONCE:
5130 DEBUG_VALID_MSG("Once branch succeeded");
5131 ret = 1;
5132 break;
5133 case XML_ELEMENT_CONTENT_PLUS:
5134 if (STATE == ROLLBACK_PARENT) {
5135 DEBUG_VALID_MSG("Plus branch rollback");
5136 ret = 1;
5137 break;
5138 }
5139 if (NODE == NULL) {
5140 DEBUG_VALID_MSG("Plus branch exhausted");
5141 ret = 1;
5142 break;
5143 }
5144 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5145 SET_OCCURRENCE;
5146 goto cont;
5147 case XML_ELEMENT_CONTENT_MULT:
5148 if (STATE == ROLLBACK_PARENT) {
5149 DEBUG_VALID_MSG("Mult branch rollback");
5150 ret = 1;
5151 break;
5152 }
5153 if (NODE == NULL) {
5154 DEBUG_VALID_MSG("Mult branch exhausted");
5155 ret = 1;
5156 break;
5157 }
5158 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5159 /* SET_OCCURRENCE; */
5160 goto cont;
5161 }
5162 }
5163 STATE = 0;
5164
5165 /*
5166 * Then act accordingly at the parent level
5167 */
5168 RESET_OCCURRENCE;
5169 if (CONT->parent == NULL)
5170 break;
5171
5172 switch (CONT->parent->type) {
5173 case XML_ELEMENT_CONTENT_PCDATA:
5174 DEBUG_VALID_MSG("Error: parent pcdata");
5175 return(-1);
5176 case XML_ELEMENT_CONTENT_ELEMENT:
5177 DEBUG_VALID_MSG("Error: parent element");
5178 return(-1);
5179 case XML_ELEMENT_CONTENT_OR:
5180 if (ret == 1) {
5181 DEBUG_VALID_MSG("Or succeeded");
5182 CONT = CONT->parent;
5183 DEPTH--;
5184 } else {
5185 DEBUG_VALID_MSG("Or failed");
5186 CONT = CONT->parent;
5187 DEPTH--;
5188 }
5189 break;
5190 case XML_ELEMENT_CONTENT_SEQ:
5191 if (ret == 0) {
5192 DEBUG_VALID_MSG("Sequence failed");
5193 CONT = CONT->parent;
5194 DEPTH--;
5195 } else if (CONT == CONT->parent->c1) {
5196 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5197 CONT = CONT->parent->c2;
5198 goto cont;
5199 } else {
5200 DEBUG_VALID_MSG("Sequence succeeded");
5201 CONT = CONT->parent;
5202 DEPTH--;
5203 }
5204 }
5205 }
5206 if (NODE != NULL) {
5207 xmlNodePtr cur;
5208
5209 cur = ctxt->vstate->node;
5210 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5211 if (vstateVPop(ctxt) < 0 ) {
5212 DEBUG_VALID_MSG("exhaustion, failed");
5213 return(0);
5214 }
5215 if (cur != ctxt->vstate->node)
5216 determinist = -3;
5217 goto cont;
5218 }
5219 if (ret == 0) {
5220 xmlNodePtr cur;
5221
5222 cur = ctxt->vstate->node;
5223 DEBUG_VALID_MSG("Failure, rollback");
5224 if (vstateVPop(ctxt) < 0 ) {
5225 DEBUG_VALID_MSG("exhaustion, failed");
5226 return(0);
5227 }
5228 if (cur != ctxt->vstate->node)
5229 determinist = -3;
5230 goto cont;
5231 }
5232 return(determinist);
5233}
5234#endif
5235
5236/**
5237 * xmlSnprintfElements:
5238 * @buf: an output buffer
5239 * @size: the size of the buffer
5240 * @content: An element
5241 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5242 *
5243 * This will dump the list of elements to the buffer
5244 * Intended just for the debug routine
5245 */
5246static void
5247xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5248 xmlNodePtr cur;
5249 int len;
5250
5251 if (node == NULL) return;
5252 if (glob) strcat(buf, "(");
5253 cur = node;
5254 while (cur != NULL) {
5255 len = strlen(buf);
5256 if (size - len < 50) {
5257 if ((size - len > 4) && (buf[len - 1] != '.'))
5258 strcat(buf, " ...");
5259 return;
5260 }
5261 switch (cur->type) {
5262 case XML_ELEMENT_NODE:
5263 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5264 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5265 if ((size - len > 4) && (buf[len - 1] != '.'))
5266 strcat(buf, " ...");
5267 return;
5268 }
5269 strcat(buf, (char *) cur->ns->prefix);
5270 strcat(buf, ":");
5271 }
5272 if (size - len < xmlStrlen(cur->name) + 10) {
5273 if ((size - len > 4) && (buf[len - 1] != '.'))
5274 strcat(buf, " ...");
5275 return;
5276 }
5277 strcat(buf, (char *) cur->name);
5278 if (cur->next != NULL)
5279 strcat(buf, " ");
5280 break;
5281 case XML_TEXT_NODE:
5282 if (xmlIsBlankNode(cur))
5283 break;
5284 /* Falls through. */
5285 case XML_CDATA_SECTION_NODE:
5286 case XML_ENTITY_REF_NODE:
5287 strcat(buf, "CDATA");
5288 if (cur->next != NULL)
5289 strcat(buf, " ");
5290 break;
5291 case XML_ATTRIBUTE_NODE:
5292 case XML_DOCUMENT_NODE:
5293#ifdef LIBXML_DOCB_ENABLED
5294 case XML_DOCB_DOCUMENT_NODE:
5295#endif
5296 case XML_HTML_DOCUMENT_NODE:
5297 case XML_DOCUMENT_TYPE_NODE:
5298 case XML_DOCUMENT_FRAG_NODE:
5299 case XML_NOTATION_NODE:
5300 case XML_NAMESPACE_DECL:
5301 strcat(buf, "???");
5302 if (cur->next != NULL)
5303 strcat(buf, " ");
5304 break;
5305 case XML_ENTITY_NODE:
5306 case XML_PI_NODE:
5307 case XML_DTD_NODE:
5308 case XML_COMMENT_NODE:
5309 case XML_ELEMENT_DECL:
5310 case XML_ATTRIBUTE_DECL:
5311 case XML_ENTITY_DECL:
5312 case XML_XINCLUDE_START:
5313 case XML_XINCLUDE_END:
5314 break;
5315 }
5316 cur = cur->next;
5317 }
5318 if (glob) strcat(buf, ")");
5319}
5320
5321/**
5322 * xmlValidateElementContent:
5323 * @ctxt: the validation context
5324 * @child: the child list
5325 * @elemDecl: pointer to the element declaration
5326 * @warn: emit the error message
5327 * @parent: the parent element (for error reporting)
5328 *
5329 * Try to validate the content model of an element
5330 *
5331 * returns 1 if valid or 0 if not and -1 in case of error
5332 */
5333
5334static int
5335xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
5336 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5337 int ret = 1;
5338#ifndef LIBXML_REGEXP_ENABLED
5339 xmlNodePtr repl = NULL, last = NULL, tmp;
5340#endif
5341 xmlNodePtr cur;
5342 xmlElementContentPtr cont;
5343 const xmlChar *name;
5344
5345 if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
5346 return(-1);
5347 cont = elemDecl->content;
5348 name = elemDecl->name;
5349
5350#ifdef LIBXML_REGEXP_ENABLED
5351 /* Build the regexp associated to the content model */
5352 if (elemDecl->contModel == NULL)
5353 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5354 if (elemDecl->contModel == NULL) {
5355 return(-1);
5356 } else {
5357 xmlRegExecCtxtPtr exec;
5358
5359 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5360 return(-1);
5361 }
5362 ctxt->nodeMax = 0;
5363 ctxt->nodeNr = 0;
5364 ctxt->nodeTab = NULL;
5365 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5366 if (exec != NULL) {
5367 cur = child;
5368 while (cur != NULL) {
5369 switch (cur->type) {
5370 case XML_ENTITY_REF_NODE:
5371 /*
5372 * Push the current node to be able to roll back
5373 * and process within the entity
5374 */
5375 if ((cur->children != NULL) &&
5376 (cur->children->children != NULL)) {
5377 nodeVPush(ctxt, cur);
5378 cur = cur->children->children;
5379 continue;
5380 }
5381 break;
5382 case XML_TEXT_NODE:
5383 if (xmlIsBlankNode(cur))
5384 break;
5385 ret = 0;
5386 goto fail;
5387 case XML_CDATA_SECTION_NODE:
5388 /* TODO */
5389 ret = 0;
5390 goto fail;
5391 case XML_ELEMENT_NODE:
5392 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5393 xmlChar fn[50];
5394 xmlChar *fullname;
5395
5396 fullname = xmlBuildQName(cur->name,
5397 cur->ns->prefix, fn, 50);
5398 if (fullname == NULL) {
5399 ret = -1;
5400 goto fail;
5401 }
5402 ret = xmlRegExecPushString(exec, fullname, NULL);
5403 if ((fullname != fn) && (fullname != cur->name))
5404 xmlFree(fullname);
5405 } else {
5406 ret = xmlRegExecPushString(exec, cur->name, NULL);
5407 }
5408 break;
5409 default:
5410 break;
5411 }
5412 /*
5413 * Switch to next element
5414 */
5415 cur = cur->next;
5416 while (cur == NULL) {
5417 cur = nodeVPop(ctxt);
5418 if (cur == NULL)
5419 break;
5420 cur = cur->next;
5421 }
5422 }
5423 ret = xmlRegExecPushString(exec, NULL, NULL);
5424fail:
5425 xmlRegFreeExecCtxt(exec);
5426 }
5427 }
5428#else /* LIBXML_REGEXP_ENABLED */
5429 /*
5430 * Allocate the stack
5431 */
5432 ctxt->vstateMax = 8;
5433 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5434 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5435 if (ctxt->vstateTab == NULL) {
5436 xmlVErrMemory(ctxt, "malloc failed");
5437 return(-1);
5438 }
5439 /*
5440 * The first entry in the stack is reserved to the current state
5441 */
5442 ctxt->nodeMax = 0;
5443 ctxt->nodeNr = 0;
5444 ctxt->nodeTab = NULL;
5445 ctxt->vstate = &ctxt->vstateTab[0];
5446 ctxt->vstateNr = 1;
5447 CONT = cont;
5448 NODE = child;
5449 DEPTH = 0;
5450 OCCURS = 0;
5451 STATE = 0;
5452 ret = xmlValidateElementType(ctxt);
5453 if ((ret == -3) && (warn)) {
5454 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5455 "Content model for Element %s is ambiguous\n",
5456 name, NULL, NULL);
5457 } else if (ret == -2) {
5458 /*
5459 * An entities reference appeared at this level.
5460 * Build a minimal representation of this node content
5461 * sufficient to run the validation process on it
5462 */
5463 DEBUG_VALID_MSG("Found an entity reference, linearizing");
5464 cur = child;
5465 while (cur != NULL) {
5466 switch (cur->type) {
5467 case XML_ENTITY_REF_NODE:
5468 /*
5469 * Push the current node to be able to roll back
5470 * and process within the entity
5471 */
5472 if ((cur->children != NULL) &&
5473 (cur->children->children != NULL)) {
5474 nodeVPush(ctxt, cur);
5475 cur = cur->children->children;
5476 continue;
5477 }
5478 break;
5479 case XML_TEXT_NODE:
5480 if (xmlIsBlankNode(cur))
5481 break;
5482 /* no break on purpose */
5483 case XML_CDATA_SECTION_NODE:
5484 /* no break on purpose */
5485 case XML_ELEMENT_NODE:
5486 /*
5487 * Allocate a new node and minimally fills in
5488 * what's required
5489 */
5490 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5491 if (tmp == NULL) {
5492 xmlVErrMemory(ctxt, "malloc failed");
5493 xmlFreeNodeList(repl);
5494 ret = -1;
5495 goto done;
5496 }
5497 tmp->type = cur->type;
5498 tmp->name = cur->name;
5499 tmp->ns = cur->ns;
5500 tmp->next = NULL;
5501 tmp->content = NULL;
5502 if (repl == NULL)
5503 repl = last = tmp;
5504 else {
5505 last->next = tmp;
5506 last = tmp;
5507 }
5508 if (cur->type == XML_CDATA_SECTION_NODE) {
5509 /*
5510 * E59 spaces in CDATA does not match the
5511 * nonterminal S
5512 */
5513 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5514 }
5515 break;
5516 default:
5517 break;
5518 }
5519 /*
5520 * Switch to next element
5521 */
5522 cur = cur->next;
5523 while (cur == NULL) {
5524 cur = nodeVPop(ctxt);
5525 if (cur == NULL)
5526 break;
5527 cur = cur->next;
5528 }
5529 }
5530
5531 /*
5532 * Relaunch the validation
5533 */
5534 ctxt->vstate = &ctxt->vstateTab[0];
5535 ctxt->vstateNr = 1;
5536 CONT = cont;
5537 NODE = repl;
5538 DEPTH = 0;
5539 OCCURS = 0;
5540 STATE = 0;
5541 ret = xmlValidateElementType(ctxt);
5542 }
5543#endif /* LIBXML_REGEXP_ENABLED */
5544 if ((warn) && ((ret != 1) && (ret != -3))) {
5545 if (ctxt != NULL) {
5546 char expr[5000];
5547 char list[5000];
5548
5549 expr[0] = 0;
5550 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5551 list[0] = 0;
5552#ifndef LIBXML_REGEXP_ENABLED
5553 if (repl != NULL)
5554 xmlSnprintfElements(&list[0], 5000, repl, 1);
5555 else
5556#endif /* LIBXML_REGEXP_ENABLED */
5557 xmlSnprintfElements(&list[0], 5000, child, 1);
5558
5559 if (name != NULL) {
5560 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5561 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5562 name, BAD_CAST expr, BAD_CAST list);
5563 } else {
5564 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5565 "Element content does not follow the DTD, expecting %s, got %s\n",
5566 BAD_CAST expr, BAD_CAST list, NULL);
5567 }
5568 } else {
5569 if (name != NULL) {
5570 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5571 "Element %s content does not follow the DTD\n",
5572 name, NULL, NULL);
5573 } else {
5574 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5575 "Element content does not follow the DTD\n",
5576 NULL, NULL, NULL);
5577 }
5578 }
5579 ret = 0;
5580 }
5581 if (ret == -3)
5582 ret = 1;
5583
5584#ifndef LIBXML_REGEXP_ENABLED
5585done:
5586 /*
5587 * Deallocate the copy if done, and free up the validation stack
5588 */
5589 while (repl != NULL) {
5590 tmp = repl->next;
5591 xmlFree(repl);
5592 repl = tmp;
5593 }
5594 ctxt->vstateMax = 0;
5595 if (ctxt->vstateTab != NULL) {
5596 xmlFree(ctxt->vstateTab);
5597 ctxt->vstateTab = NULL;
5598 }
5599#endif
5600 ctxt->nodeMax = 0;
5601 ctxt->nodeNr = 0;
5602 if (ctxt->nodeTab != NULL) {
5603 xmlFree(ctxt->nodeTab);
5604 ctxt->nodeTab = NULL;
5605 }
5606 return(ret);
5607
5608}
5609
5610/**
5611 * xmlValidateCdataElement:
5612 * @ctxt: the validation context
5613 * @doc: a document instance
5614 * @elem: an element instance
5615 *
5616 * Check that an element follows #CDATA
5617 *
5618 * returns 1 if valid or 0 otherwise
5619 */
5620static int
5621xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5622 xmlNodePtr elem) {
5623 int ret = 1;
5624 xmlNodePtr cur, child;
5625
5626 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5627 (elem->type != XML_ELEMENT_NODE))
5628 return(0);
5629
5630 child = elem->children;
5631
5632 cur = child;
5633 while (cur != NULL) {
5634 switch (cur->type) {
5635 case XML_ENTITY_REF_NODE:
5636 /*
5637 * Push the current node to be able to roll back
5638 * and process within the entity
5639 */
5640 if ((cur->children != NULL) &&
5641 (cur->children->children != NULL)) {
5642 nodeVPush(ctxt, cur);
5643 cur = cur->children->children;
5644 continue;
5645 }
5646 break;
5647 case XML_COMMENT_NODE:
5648 case XML_PI_NODE:
5649 case XML_TEXT_NODE:
5650 case XML_CDATA_SECTION_NODE:
5651 break;
5652 default:
5653 ret = 0;
5654 goto done;
5655 }
5656 /*
5657 * Switch to next element
5658 */
5659 cur = cur->next;
5660 while (cur == NULL) {
5661 cur = nodeVPop(ctxt);
5662 if (cur == NULL)
5663 break;
5664 cur = cur->next;
5665 }
5666 }
5667done:
5668 ctxt->nodeMax = 0;
5669 ctxt->nodeNr = 0;
5670 if (ctxt->nodeTab != NULL) {
5671 xmlFree(ctxt->nodeTab);
5672 ctxt->nodeTab = NULL;
5673 }
5674 return(ret);
5675}
5676
5677/**
5678 * xmlValidateCheckMixed:
5679 * @ctxt: the validation context
5680 * @cont: the mixed content model
5681 * @qname: the qualified name as appearing in the serialization
5682 *
5683 * Check if the given node is part of the content model.
5684 *
5685 * Returns 1 if yes, 0 if no, -1 in case of error
5686 */
5687static int
5688xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
5689 xmlElementContentPtr cont, const xmlChar *qname) {
5690 const xmlChar *name;
5691 int plen;
5692 name = xmlSplitQName3(qname, &plen);
5693
5694 if (name == NULL) {
5695 while (cont != NULL) {
5696 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5697 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5698 return(1);
5699 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5700 (cont->c1 != NULL) &&
5701 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5702 if ((cont->c1->prefix == NULL) &&
5703 (xmlStrEqual(cont->c1->name, qname)))
5704 return(1);
5705 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5706 (cont->c1 == NULL) ||
5707 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5708 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5709 "Internal: MIXED struct corrupted\n",
5710 NULL);
5711 break;
5712 }
5713 cont = cont->c2;
5714 }
5715 } else {
5716 while (cont != NULL) {
5717 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5718 if ((cont->prefix != NULL) &&
5719 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5720 (xmlStrEqual(cont->name, name)))
5721 return(1);
5722 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5723 (cont->c1 != NULL) &&
5724 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5725 if ((cont->c1->prefix != NULL) &&
5726 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5727 (xmlStrEqual(cont->c1->name, name)))
5728 return(1);
5729 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5730 (cont->c1 == NULL) ||
5731 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5732 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5733 "Internal: MIXED struct corrupted\n",
5734 NULL);
5735 break;
5736 }
5737 cont = cont->c2;
5738 }
5739 }
5740 return(0);
5741}
5742
5743/**
5744 * xmlValidGetElemDecl:
5745 * @ctxt: the validation context
5746 * @doc: a document instance
5747 * @elem: an element instance
5748 * @extsubset: pointer, (out) indicate if the declaration was found
5749 * in the external subset.
5750 *
5751 * Finds a declaration associated to an element in the document.
5752 *
5753 * returns the pointer to the declaration or NULL if not found.
5754 */
5755static xmlElementPtr
5756xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5757 xmlNodePtr elem, int *extsubset) {
5758 xmlElementPtr elemDecl = NULL;
5759 const xmlChar *prefix = NULL;
5760
5761 if ((ctxt == NULL) || (doc == NULL) ||
5762 (elem == NULL) || (elem->name == NULL))
5763 return(NULL);
5764 if (extsubset != NULL)
5765 *extsubset = 0;
5766
5767 /*
5768 * Fetch the declaration for the qualified name
5769 */
5770 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5771 prefix = elem->ns->prefix;
5772
5773 if (prefix != NULL) {
5774 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5775 elem->name, prefix);
5776 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5777 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5778 elem->name, prefix);
5779 if ((elemDecl != NULL) && (extsubset != NULL))
5780 *extsubset = 1;
5781 }
5782 }
5783
5784 /*
5785 * Fetch the declaration for the non qualified name
5786 * This is "non-strict" validation should be done on the
5787 * full QName but in that case being flexible makes sense.
5788 */
5789 if (elemDecl == NULL) {
5790 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5791 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5792 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5793 if ((elemDecl != NULL) && (extsubset != NULL))
5794 *extsubset = 1;
5795 }
5796 }
5797 if (elemDecl == NULL) {
5798 xmlErrValidNode(ctxt, elem,
5799 XML_DTD_UNKNOWN_ELEM,
5800 "No declaration for element %s\n",
5801 elem->name, NULL, NULL);
5802 }
5803 return(elemDecl);
5804}
5805
5806#ifdef LIBXML_REGEXP_ENABLED
5807/**
5808 * xmlValidatePushElement:
5809 * @ctxt: the validation context
5810 * @doc: a document instance
5811 * @elem: an element instance
5812 * @qname: the qualified name as appearing in the serialization
5813 *
5814 * Push a new element start on the validation stack.
5815 *
5816 * returns 1 if no validation problem was found or 0 otherwise
5817 */
5818int
5819xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5820 xmlNodePtr elem, const xmlChar *qname) {
5821 int ret = 1;
5822 xmlElementPtr eDecl;
5823 int extsubset = 0;
5824
5825 if (ctxt == NULL)
5826 return(0);
5827/* printf("PushElem %s\n", qname); */
5828 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5829 xmlValidStatePtr state = ctxt->vstate;
5830 xmlElementPtr elemDecl;
5831
5832 /*
5833 * Check the new element against the content model of the new elem.
5834 */
5835 if (state->elemDecl != NULL) {
5836 elemDecl = state->elemDecl;
5837
5838 switch(elemDecl->etype) {
5839 case XML_ELEMENT_TYPE_UNDEFINED:
5840 ret = 0;
5841 break;
5842 case XML_ELEMENT_TYPE_EMPTY:
5843 xmlErrValidNode(ctxt, state->node,
5844 XML_DTD_NOT_EMPTY,
5845 "Element %s was declared EMPTY this one has content\n",
5846 state->node->name, NULL, NULL);
5847 ret = 0;
5848 break;
5849 case XML_ELEMENT_TYPE_ANY:
5850 /* I don't think anything is required then */
5851 break;
5852 case XML_ELEMENT_TYPE_MIXED:
5853 /* simple case of declared as #PCDATA */
5854 if ((elemDecl->content != NULL) &&
5855 (elemDecl->content->type ==
5856 XML_ELEMENT_CONTENT_PCDATA)) {
5857 xmlErrValidNode(ctxt, state->node,
5858 XML_DTD_NOT_PCDATA,
5859 "Element %s was declared #PCDATA but contains non text nodes\n",
5860 state->node->name, NULL, NULL);
5861 ret = 0;
5862 } else {
5863 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5864 qname);
5865 if (ret != 1) {
5866 xmlErrValidNode(ctxt, state->node,
5867 XML_DTD_INVALID_CHILD,
5868 "Element %s is not declared in %s list of possible children\n",
5869 qname, state->node->name, NULL);
5870 }
5871 }
5872 break;
5873 case XML_ELEMENT_TYPE_ELEMENT:
5874 /*
5875 * TODO:
5876 * VC: Standalone Document Declaration
5877 * - element types with element content, if white space
5878 * occurs directly within any instance of those types.
5879 */
5880 if (state->exec != NULL) {
5881 ret = xmlRegExecPushString(state->exec, qname, NULL);
5882 if (ret < 0) {
5883 xmlErrValidNode(ctxt, state->node,
5884 XML_DTD_CONTENT_MODEL,
5885 "Element %s content does not follow the DTD, Misplaced %s\n",
5886 state->node->name, qname, NULL);
5887 ret = 0;
5888 } else {
5889 ret = 1;
5890 }
5891 }
5892 break;
5893 }
5894 }
5895 }
5896 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5897 vstateVPush(ctxt, eDecl, elem);
5898 return(ret);
5899}
5900
5901/**
5902 * xmlValidatePushCData:
5903 * @ctxt: the validation context
5904 * @data: some character data read
5905 * @len: the length of the data
5906 *
5907 * check the CData parsed for validation in the current stack
5908 *
5909 * returns 1 if no validation problem was found or 0 otherwise
5910 */
5911int
5912xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5913 int ret = 1;
5914
5915/* printf("CDATA %s %d\n", data, len); */
5916 if (ctxt == NULL)
5917 return(0);
5918 if (len <= 0)
5919 return(ret);
5920 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5921 xmlValidStatePtr state = ctxt->vstate;
5922 xmlElementPtr elemDecl;
5923
5924 /*
5925 * Check the new element against the content model of the new elem.
5926 */
5927 if (state->elemDecl != NULL) {
5928 elemDecl = state->elemDecl;
5929
5930 switch(elemDecl->etype) {
5931 case XML_ELEMENT_TYPE_UNDEFINED:
5932 ret = 0;
5933 break;
5934 case XML_ELEMENT_TYPE_EMPTY:
5935 xmlErrValidNode(ctxt, state->node,
5936 XML_DTD_NOT_EMPTY,
5937 "Element %s was declared EMPTY this one has content\n",
5938 state->node->name, NULL, NULL);
5939 ret = 0;
5940 break;
5941 case XML_ELEMENT_TYPE_ANY:
5942 break;
5943 case XML_ELEMENT_TYPE_MIXED:
5944 break;
5945 case XML_ELEMENT_TYPE_ELEMENT: {
5946 int i;
5947
5948 for (i = 0;i < len;i++) {
5949 if (!IS_BLANK_CH(data[i])) {
5950 xmlErrValidNode(ctxt, state->node,
5951 XML_DTD_CONTENT_MODEL,
5952 "Element %s content does not follow the DTD, Text not allowed\n",
5953 state->node->name, NULL, NULL);
5954 ret = 0;
5955 goto done;
5956 }
5957 }
5958 /*
5959 * TODO:
5960 * VC: Standalone Document Declaration
5961 * element types with element content, if white space
5962 * occurs directly within any instance of those types.
5963 */
5964 break;
5965 }
5966 }
5967 }
5968 }
5969done:
5970 return(ret);
5971}
5972
5973/**
5974 * xmlValidatePopElement:
5975 * @ctxt: the validation context
5976 * @doc: a document instance
5977 * @elem: an element instance
5978 * @qname: the qualified name as appearing in the serialization
5979 *
5980 * Pop the element end from the validation stack.
5981 *
5982 * returns 1 if no validation problem was found or 0 otherwise
5983 */
5984int
5985xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
5986 xmlNodePtr elem ATTRIBUTE_UNUSED,
5987 const xmlChar *qname ATTRIBUTE_UNUSED) {
5988 int ret = 1;
5989
5990 if (ctxt == NULL)
5991 return(0);
5992/* printf("PopElem %s\n", qname); */
5993 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5994 xmlValidStatePtr state = ctxt->vstate;
5995 xmlElementPtr elemDecl;
5996
5997 /*
5998 * Check the new element against the content model of the new elem.
5999 */
6000 if (state->elemDecl != NULL) {
6001 elemDecl = state->elemDecl;
6002
6003 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
6004 if (state->exec != NULL) {
6005 ret = xmlRegExecPushString(state->exec, NULL, NULL);
6006 if (ret == 0) {
6007 xmlErrValidNode(ctxt, state->node,
6008 XML_DTD_CONTENT_MODEL,
6009 "Element %s content does not follow the DTD, Expecting more child\n",
6010 state->node->name, NULL,NULL);
6011 } else {
6012 /*
6013 * previous validation errors should not generate
6014 * a new one here
6015 */
6016 ret = 1;
6017 }
6018 }
6019 }
6020 }
6021 vstateVPop(ctxt);
6022 }
6023 return(ret);
6024}
6025#endif /* LIBXML_REGEXP_ENABLED */
6026
6027/**
6028 * xmlValidateOneElement:
6029 * @ctxt: the validation context
6030 * @doc: a document instance
6031 * @elem: an element instance
6032 *
6033 * Try to validate a single element and it's attributes,
6034 * basically it does the following checks as described by the
6035 * XML-1.0 recommendation:
6036 * - [ VC: Element Valid ]
6037 * - [ VC: Required Attribute ]
6038 * Then call xmlValidateOneAttribute() for each attribute present.
6039 *
6040 * The ID/IDREF checkings are done separately
6041 *
6042 * returns 1 if valid or 0 otherwise
6043 */
6044
6045int
6046xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
6047 xmlNodePtr elem) {
6048 xmlElementPtr elemDecl = NULL;
6049 xmlElementContentPtr cont;
6050 xmlAttributePtr attr;
6051 xmlNodePtr child;
6052 int ret = 1, tmp;
6053 const xmlChar *name;
6054 int extsubset = 0;
6055
6056 CHECK_DTD;
6057
6058 if (elem == NULL) return(0);
6059 switch (elem->type) {
6060 case XML_ATTRIBUTE_NODE:
6061 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6062 "Attribute element not expected\n", NULL, NULL ,NULL);
6063 return(0);
6064 case XML_TEXT_NODE:
6065 if (elem->children != NULL) {
6066 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6067 "Text element has children !\n",
6068 NULL,NULL,NULL);
6069 return(0);
6070 }
6071 if (elem->ns != NULL) {
6072 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6073 "Text element has namespace !\n",
6074 NULL,NULL,NULL);
6075 return(0);
6076 }
6077 if (elem->content == NULL) {
6078 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6079 "Text element has no content !\n",
6080 NULL,NULL,NULL);
6081 return(0);
6082 }
6083 return(1);
6084 case XML_XINCLUDE_START:
6085 case XML_XINCLUDE_END:
6086 return(1);
6087 case XML_CDATA_SECTION_NODE:
6088 case XML_ENTITY_REF_NODE:
6089 case XML_PI_NODE:
6090 case XML_COMMENT_NODE:
6091 return(1);
6092 case XML_ENTITY_NODE:
6093 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6094 "Entity element not expected\n", NULL, NULL ,NULL);
6095 return(0);
6096 case XML_NOTATION_NODE:
6097 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6098 "Notation element not expected\n", NULL, NULL ,NULL);
6099 return(0);
6100 case XML_DOCUMENT_NODE:
6101 case XML_DOCUMENT_TYPE_NODE:
6102 case XML_DOCUMENT_FRAG_NODE:
6103 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6104 "Document element not expected\n", NULL, NULL ,NULL);
6105 return(0);
6106 case XML_HTML_DOCUMENT_NODE:
6107 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6108 "HTML Document not expected\n", NULL, NULL ,NULL);
6109 return(0);
6110 case XML_ELEMENT_NODE:
6111 break;
6112 default:
6113 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6114 "unknown element type\n", NULL, NULL ,NULL);
6115 return(0);
6116 }
6117
6118 /*
6119 * Fetch the declaration
6120 */
6121 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6122 if (elemDecl == NULL)
6123 return(0);
6124
6125 /*
6126 * If vstateNr is not zero that means continuous validation is
6127 * activated, do not try to check the content model at that level.
6128 */
6129 if (ctxt->vstateNr == 0) {
6130 /* Check that the element content matches the definition */
6131 switch (elemDecl->etype) {
6132 case XML_ELEMENT_TYPE_UNDEFINED:
6133 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6134 "No declaration for element %s\n",
6135 elem->name, NULL, NULL);
6136 return(0);
6137 case XML_ELEMENT_TYPE_EMPTY:
6138 if (elem->children != NULL) {
6139 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
6140 "Element %s was declared EMPTY this one has content\n",
6141 elem->name, NULL, NULL);
6142 ret = 0;
6143 }
6144 break;
6145 case XML_ELEMENT_TYPE_ANY:
6146 /* I don't think anything is required then */
6147 break;
6148 case XML_ELEMENT_TYPE_MIXED:
6149
6150 /* simple case of declared as #PCDATA */
6151 if ((elemDecl->content != NULL) &&
6152 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6153 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6154 if (!ret) {
6155 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
6156 "Element %s was declared #PCDATA but contains non text nodes\n",
6157 elem->name, NULL, NULL);
6158 }
6159 break;
6160 }
6161 child = elem->children;
6162 /* Hum, this start to get messy */
6163 while (child != NULL) {
6164 if (child->type == XML_ELEMENT_NODE) {
6165 name = child->name;
6166 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
6167 xmlChar fn[50];
6168 xmlChar *fullname;
6169
6170 fullname = xmlBuildQName(child->name, child->ns->prefix,
6171 fn, 50);
6172 if (fullname == NULL)
6173 return(0);
6174 cont = elemDecl->content;
6175 while (cont != NULL) {
6176 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6177 if (xmlStrEqual(cont->name, fullname))
6178 break;
6179 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6180 (cont->c1 != NULL) &&
6181 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
6182 if (xmlStrEqual(cont->c1->name, fullname))
6183 break;
6184 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6185 (cont->c1 == NULL) ||
6186 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
6187 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
6188 "Internal: MIXED struct corrupted\n",
6189 NULL);
6190 break;
6191 }
6192 cont = cont->c2;
6193 }
6194 if ((fullname != fn) && (fullname != child->name))
6195 xmlFree(fullname);
6196 if (cont != NULL)
6197 goto child_ok;
6198 }
6199 cont = elemDecl->content;
6200 while (cont != NULL) {
6201 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6202 if (xmlStrEqual(cont->name, name)) break;
6203 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6204 (cont->c1 != NULL) &&
6205 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6206 if (xmlStrEqual(cont->c1->name, name)) break;
6207 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6208 (cont->c1 == NULL) ||
6209 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
6210 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6211 "Internal: MIXED struct corrupted\n",
6212 NULL);
6213 break;
6214 }
6215 cont = cont->c2;
6216 }
6217 if (cont == NULL) {
6218 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
6219 "Element %s is not declared in %s list of possible children\n",
6220 name, elem->name, NULL);
6221 ret = 0;
6222 }
6223 }
6224child_ok:
6225 child = child->next;
6226 }
6227 break;
6228 case XML_ELEMENT_TYPE_ELEMENT:
6229 if ((doc->standalone == 1) && (extsubset == 1)) {
6230 /*
6231 * VC: Standalone Document Declaration
6232 * - element types with element content, if white space
6233 * occurs directly within any instance of those types.
6234 */
6235 child = elem->children;
6236 while (child != NULL) {
6237 if (child->type == XML_TEXT_NODE) {
6238 const xmlChar *content = child->content;
6239
6240 while (IS_BLANK_CH(*content))
6241 content++;
6242 if (*content == 0) {
6243 xmlErrValidNode(ctxt, elem,
6244 XML_DTD_STANDALONE_WHITE_SPACE,
6245"standalone: %s declared in the external subset contains white spaces nodes\n",
6246 elem->name, NULL, NULL);
6247 ret = 0;
6248 break;
6249 }
6250 }
6251 child =child->next;
6252 }
6253 }
6254 child = elem->children;
6255 cont = elemDecl->content;
6256 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
6257 if (tmp <= 0)
6258 ret = tmp;
6259 break;
6260 }
6261 } /* not continuous */
6262
6263 /* [ VC: Required Attribute ] */
6264 attr = elemDecl->attributes;
6265 while (attr != NULL) {
6266 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6267 int qualified = -1;
6268
6269 if ((attr->prefix == NULL) &&
6270 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6271 xmlNsPtr ns;
6272
6273 ns = elem->nsDef;
6274 while (ns != NULL) {
6275 if (ns->prefix == NULL)
6276 goto found;
6277 ns = ns->next;
6278 }
6279 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6280 xmlNsPtr ns;
6281
6282 ns = elem->nsDef;
6283 while (ns != NULL) {
6284 if (xmlStrEqual(attr->name, ns->prefix))
6285 goto found;
6286 ns = ns->next;
6287 }
6288 } else {
6289 xmlAttrPtr attrib;
6290
6291 attrib = elem->properties;
6292 while (attrib != NULL) {
6293 if (xmlStrEqual(attrib->name, attr->name)) {
6294 if (attr->prefix != NULL) {
6295 xmlNsPtr nameSpace = attrib->ns;
6296
6297 if (nameSpace == NULL)
6298 nameSpace = elem->ns;
6299 /*
6300 * qualified names handling is problematic, having a
6301 * different prefix should be possible but DTDs don't
6302 * allow to define the URI instead of the prefix :-(
6303 */
6304 if (nameSpace == NULL) {
6305 if (qualified < 0)
6306 qualified = 0;
6307 } else if (!xmlStrEqual(nameSpace->prefix,
6308 attr->prefix)) {
6309 if (qualified < 1)
6310 qualified = 1;
6311 } else
6312 goto found;
6313 } else {
6314 /*
6315 * We should allow applications to define namespaces
6316 * for their application even if the DTD doesn't
6317 * carry one, otherwise, basically we would always
6318 * break.
6319 */
6320 goto found;
6321 }
6322 }
6323 attrib = attrib->next;
6324 }
6325 }
6326 if (qualified == -1) {
6327 if (attr->prefix == NULL) {
6328 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6329 "Element %s does not carry attribute %s\n",
6330 elem->name, attr->name, NULL);
6331 ret = 0;
6332 } else {
6333 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6334 "Element %s does not carry attribute %s:%s\n",
6335 elem->name, attr->prefix,attr->name);
6336 ret = 0;
6337 }
6338 } else if (qualified == 0) {
6339 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6340 "Element %s required attribute %s:%s has no prefix\n",
6341 elem->name, attr->prefix, attr->name);
6342 } else if (qualified == 1) {
6343 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6344 "Element %s required attribute %s:%s has different prefix\n",
6345 elem->name, attr->prefix, attr->name);
6346 }
6347 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6348 /*
6349 * Special tests checking #FIXED namespace declarations
6350 * have the right value since this is not done as an
6351 * attribute checking
6352 */
6353 if ((attr->prefix == NULL) &&
6354 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6355 xmlNsPtr ns;
6356
6357 ns = elem->nsDef;
6358 while (ns != NULL) {
6359 if (ns->prefix == NULL) {
6360 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6361 xmlErrValidNode(ctxt, elem,
6362 XML_DTD_ELEM_DEFAULT_NAMESPACE,
6363 "Element %s namespace name for default namespace does not match the DTD\n",
6364 elem->name, NULL, NULL);
6365 ret = 0;
6366 }
6367 goto found;
6368 }
6369 ns = ns->next;
6370 }
6371 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6372 xmlNsPtr ns;
6373
6374 ns = elem->nsDef;
6375 while (ns != NULL) {
6376 if (xmlStrEqual(attr->name, ns->prefix)) {
6377 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6378 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6379 "Element %s namespace name for %s does not match the DTD\n",
6380 elem->name, ns->prefix, NULL);
6381 ret = 0;
6382 }
6383 goto found;
6384 }
6385 ns = ns->next;
6386 }
6387 }
6388 }
6389found:
6390 attr = attr->nexth;
6391 }
6392 return(ret);
6393}
6394
6395/**
6396 * xmlValidateRoot:
6397 * @ctxt: the validation context
6398 * @doc: a document instance
6399 *
6400 * Try to validate a the root element
6401 * basically it does the following check as described by the
6402 * XML-1.0 recommendation:
6403 * - [ VC: Root Element Type ]
6404 * it doesn't try to recurse or apply other check to the element
6405 *
6406 * returns 1 if valid or 0 otherwise
6407 */
6408
6409int
6410xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6411 xmlNodePtr root;
6412 int ret;
6413
6414 if (doc == NULL) return(0);
6415
6416 root = xmlDocGetRootElement(doc);
6417 if ((root == NULL) || (root->name == NULL)) {
6418 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6419 "no root element\n", NULL);
6420 return(0);
6421 }
6422
6423 /*
6424 * When doing post validation against a separate DTD, those may
6425 * no internal subset has been generated
6426 */
6427 if ((doc->intSubset != NULL) &&
6428 (doc->intSubset->name != NULL)) {
6429 /*
6430 * Check first the document root against the NQName
6431 */
6432 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6433 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6434 xmlChar fn[50];
6435 xmlChar *fullname;
6436
6437 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6438 if (fullname == NULL) {
6439 xmlVErrMemory(ctxt, NULL);
6440 return(0);
6441 }
6442 ret = xmlStrEqual(doc->intSubset->name, fullname);
6443 if ((fullname != fn) && (fullname != root->name))
6444 xmlFree(fullname);
6445 if (ret == 1)
6446 goto name_ok;
6447 }
6448 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6449 (xmlStrEqual(root->name, BAD_CAST "html")))
6450 goto name_ok;
6451 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6452 "root and DTD name do not match '%s' and '%s'\n",
6453 root->name, doc->intSubset->name, NULL);
6454 return(0);
6455 }
6456 }
6457name_ok:
6458 return(1);
6459}
6460
6461
6462/**
6463 * xmlValidateElement:
6464 * @ctxt: the validation context
6465 * @doc: a document instance
6466 * @elem: an element instance
6467 *
6468 * Try to validate the subtree under an element
6469 *
6470 * returns 1 if valid or 0 otherwise
6471 */
6472
6473int
6474xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6475 xmlNodePtr child;
6476 xmlAttrPtr attr;
6477 xmlNsPtr ns;
6478 const xmlChar *value;
6479 int ret = 1;
6480
6481 if (elem == NULL) return(0);
6482
6483 /*
6484 * XInclude elements were added after parsing in the infoset,
6485 * they don't really mean anything validation wise.
6486 */
6487 if ((elem->type == XML_XINCLUDE_START) ||
6488 (elem->type == XML_XINCLUDE_END) ||
6489 (elem->type == XML_NAMESPACE_DECL))
6490 return(1);
6491
6492 CHECK_DTD;
6493
6494 /*
6495 * Entities references have to be handled separately
6496 */
6497 if (elem->type == XML_ENTITY_REF_NODE) {
6498 return(1);
6499 }
6500
6501 ret &= xmlValidateOneElement(ctxt, doc, elem);
6502 if (elem->type == XML_ELEMENT_NODE) {
6503 attr = elem->properties;
6504 while (attr != NULL) {
6505 value = xmlNodeListGetString(doc, attr->children, 0);
6506 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6507 if (value != NULL)
6508 xmlFree((char *)value);
6509 attr= attr->next;
6510 }
6511 ns = elem->nsDef;
6512 while (ns != NULL) {
6513 if (elem->ns == NULL)
6514 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6515 ns, ns->href);
6516 else
6517 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6518 elem->ns->prefix, ns, ns->href);
6519 ns = ns->next;
6520 }
6521 }
6522 child = elem->children;
6523 while (child != NULL) {
6524 ret &= xmlValidateElement(ctxt, doc, child);
6525 child = child->next;
6526 }
6527
6528 return(ret);
6529}
6530
6531/**
6532 * xmlValidateRef:
6533 * @ref: A reference to be validated
6534 * @ctxt: Validation context
6535 * @name: Name of ID we are searching for
6536 *
6537 */
6538static void
6539xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
6540 const xmlChar *name) {
6541 xmlAttrPtr id;
6542 xmlAttrPtr attr;
6543
6544 if (ref == NULL)
6545 return;
6546 if ((ref->attr == NULL) && (ref->name == NULL))
6547 return;
6548 attr = ref->attr;
6549 if (attr == NULL) {
6550 xmlChar *dup, *str = NULL, *cur, save;
6551
6552 dup = xmlStrdup(name);
6553 if (dup == NULL) {
6554 ctxt->valid = 0;
6555 return;
6556 }
6557 cur = dup;
6558 while (*cur != 0) {
6559 str = cur;
6560 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6561 save = *cur;
6562 *cur = 0;
6563 id = xmlGetID(ctxt->doc, str);
6564 if (id == NULL) {
6565 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6566 "attribute %s line %d references an unknown ID \"%s\"\n",
6567 ref->name, ref->lineno, str);
6568 ctxt->valid = 0;
6569 }
6570 if (save == 0)
6571 break;
6572 *cur = save;
6573 while (IS_BLANK_CH(*cur)) cur++;
6574 }
6575 xmlFree(dup);
6576 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6577 id = xmlGetID(ctxt->doc, name);
6578 if (id == NULL) {
6579 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6580 "IDREF attribute %s references an unknown ID \"%s\"\n",
6581 attr->name, name, NULL);
6582 ctxt->valid = 0;
6583 }
6584 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6585 xmlChar *dup, *str = NULL, *cur, save;
6586
6587 dup = xmlStrdup(name);
6588 if (dup == NULL) {
6589 xmlVErrMemory(ctxt, "IDREFS split");
6590 ctxt->valid = 0;
6591 return;
6592 }
6593 cur = dup;
6594 while (*cur != 0) {
6595 str = cur;
6596 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6597 save = *cur;
6598 *cur = 0;
6599 id = xmlGetID(ctxt->doc, str);
6600 if (id == NULL) {
6601 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6602 "IDREFS attribute %s references an unknown ID \"%s\"\n",
6603 attr->name, str, NULL);
6604 ctxt->valid = 0;
6605 }
6606 if (save == 0)
6607 break;
6608 *cur = save;
6609 while (IS_BLANK_CH(*cur)) cur++;
6610 }
6611 xmlFree(dup);
6612 }
6613}
6614
6615/**
6616 * xmlWalkValidateList:
6617 * @data: Contents of current link
6618 * @user: Value supplied by the user
6619 *
6620 * Returns 0 to abort the walk or 1 to continue
6621 */
6622static int
6623xmlWalkValidateList(const void *data, void *user)
6624{
6625 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6626 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6627 return 1;
6628}
6629
6630/**
6631 * xmlValidateCheckRefCallback:
6632 * @ref_list: List of references
6633 * @ctxt: Validation context
6634 * @name: Name of ID we are searching for
6635 *
6636 */
6637static void
6638xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) {
6639 xmlListPtr ref_list = (xmlListPtr) payload;
6640 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6641 xmlValidateMemo memo;
6642
6643 if (ref_list == NULL)
6644 return;
6645 memo.ctxt = ctxt;
6646 memo.name = name;
6647
6648 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6649
6650}
6651
6652/**
6653 * xmlValidateDocumentFinal:
6654 * @ctxt: the validation context
6655 * @doc: a document instance
6656 *
6657 * Does the final step for the document validation once all the
6658 * incremental validation steps have been completed
6659 *
6660 * basically it does the following checks described by the XML Rec
6661 *
6662 * Check all the IDREF/IDREFS attributes definition for validity
6663 *
6664 * returns 1 if valid or 0 otherwise
6665 */
6666
6667int
6668xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6669 xmlRefTablePtr table;
6670 unsigned int save;
6671
6672 if (ctxt == NULL)
6673 return(0);
6674 if (doc == NULL) {
6675 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6676 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
6677 return(0);
6678 }
6679
6680 /* trick to get correct line id report */
6681 save = ctxt->finishDtd;
6682 ctxt->finishDtd = 0;
6683
6684 /*
6685 * Check all the NOTATION/NOTATIONS attributes
6686 */
6687 /*
6688 * Check all the ENTITY/ENTITIES attributes definition for validity
6689 */
6690 /*
6691 * Check all the IDREF/IDREFS attributes definition for validity
6692 */
6693 table = (xmlRefTablePtr) doc->refs;
6694 ctxt->doc = doc;
6695 ctxt->valid = 1;
6696 xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
6697
6698 ctxt->finishDtd = save;
6699 return(ctxt->valid);
6700}
6701
6702/**
6703 * xmlValidateDtd:
6704 * @ctxt: the validation context
6705 * @doc: a document instance
6706 * @dtd: a dtd instance
6707 *
6708 * Try to validate the document against the dtd instance
6709 *
6710 * Basically it does check all the definitions in the DtD.
6711 * Note the the internal subset (if present) is de-coupled
6712 * (i.e. not used), which could give problems if ID or IDREF
6713 * is present.
6714 *
6715 * returns 1 if valid or 0 otherwise
6716 */
6717
6718int
6719xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6720 int ret;
6721 xmlDtdPtr oldExt, oldInt;
6722 xmlNodePtr root;
6723
6724 if (dtd == NULL) return(0);
6725 if (doc == NULL) return(0);
6726 oldExt = doc->extSubset;
6727 oldInt = doc->intSubset;
6728 doc->extSubset = dtd;
6729 doc->intSubset = NULL;
6730 ret = xmlValidateRoot(ctxt, doc);
6731 if (ret == 0) {
6732 doc->extSubset = oldExt;
6733 doc->intSubset = oldInt;
6734 return(ret);
6735 }
6736 if (doc->ids != NULL) {
6737 xmlFreeIDTable(doc->ids);
6738 doc->ids = NULL;
6739 }
6740 if (doc->refs != NULL) {
6741 xmlFreeRefTable(doc->refs);
6742 doc->refs = NULL;
6743 }
6744 root = xmlDocGetRootElement(doc);
6745 ret = xmlValidateElement(ctxt, doc, root);
6746 ret &= xmlValidateDocumentFinal(ctxt, doc);
6747 doc->extSubset = oldExt;
6748 doc->intSubset = oldInt;
6749 return(ret);
6750}
6751
6752static void
6753xmlValidateNotationCallback(void *payload, void *data,
6754 const xmlChar *name ATTRIBUTE_UNUSED) {
6755 xmlEntityPtr cur = (xmlEntityPtr) payload;
6756 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6757 if (cur == NULL)
6758 return;
6759 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6760 xmlChar *notation = cur->content;
6761
6762 if (notation != NULL) {
6763 int ret;
6764
6765 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6766 if (ret != 1) {
6767 ctxt->valid = 0;
6768 }
6769 }
6770 }
6771}
6772
6773static void
6774xmlValidateAttributeCallback(void *payload, void *data,
6775 const xmlChar *name ATTRIBUTE_UNUSED) {
6776 xmlAttributePtr cur = (xmlAttributePtr) payload;
6777 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6778 int ret;
6779 xmlDocPtr doc;
6780 xmlElementPtr elem = NULL;
6781
6782 if (cur == NULL)
6783 return;
6784 switch (cur->atype) {
6785 case XML_ATTRIBUTE_CDATA:
6786 case XML_ATTRIBUTE_ID:
6787 case XML_ATTRIBUTE_IDREF :
6788 case XML_ATTRIBUTE_IDREFS:
6789 case XML_ATTRIBUTE_NMTOKEN:
6790 case XML_ATTRIBUTE_NMTOKENS:
6791 case XML_ATTRIBUTE_ENUMERATION:
6792 break;
6793 case XML_ATTRIBUTE_ENTITY:
6794 case XML_ATTRIBUTE_ENTITIES:
6795 case XML_ATTRIBUTE_NOTATION:
6796 if (cur->defaultValue != NULL) {
6797
6798 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6799 cur->atype, cur->defaultValue);
6800 if ((ret == 0) && (ctxt->valid == 1))
6801 ctxt->valid = 0;
6802 }
6803 if (cur->tree != NULL) {
6804 xmlEnumerationPtr tree = cur->tree;
6805 while (tree != NULL) {
6806 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6807 cur->name, cur->atype, tree->name);
6808 if ((ret == 0) && (ctxt->valid == 1))
6809 ctxt->valid = 0;
6810 tree = tree->next;
6811 }
6812 }
6813 }
6814 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6815 doc = cur->doc;
6816 if (cur->elem == NULL) {
6817 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
6818 "xmlValidateAttributeCallback(%s): internal error\n",
6819 (const char *) cur->name);
6820 return;
6821 }
6822
6823 if (doc != NULL)
6824 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6825 if ((elem == NULL) && (doc != NULL))
6826 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6827 if ((elem == NULL) && (cur->parent != NULL) &&
6828 (cur->parent->type == XML_DTD_NODE))
6829 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
6830 if (elem == NULL) {
6831 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
6832 "attribute %s: could not find decl for element %s\n",
6833 cur->name, cur->elem, NULL);
6834 return;
6835 }
6836 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6837 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6838 "NOTATION attribute %s declared for EMPTY element %s\n",
6839 cur->name, cur->elem, NULL);
6840 ctxt->valid = 0;
6841 }
6842 }
6843}
6844
6845/**
6846 * xmlValidateDtdFinal:
6847 * @ctxt: the validation context
6848 * @doc: a document instance
6849 *
6850 * Does the final step for the dtds validation once all the
6851 * subsets have been parsed
6852 *
6853 * basically it does the following checks described by the XML Rec
6854 * - check that ENTITY and ENTITIES type attributes default or
6855 * possible values matches one of the defined entities.
6856 * - check that NOTATION type attributes default or
6857 * possible values matches one of the defined notations.
6858 *
6859 * returns 1 if valid or 0 if invalid and -1 if not well-formed
6860 */
6861
6862int
6863xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6864 xmlDtdPtr dtd;
6865 xmlAttributeTablePtr table;
6866 xmlEntitiesTablePtr entities;
6867
6868 if ((doc == NULL) || (ctxt == NULL)) return(0);
6869 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6870 return(0);
6871 ctxt->doc = doc;
6872 ctxt->valid = 1;
6873 dtd = doc->intSubset;
6874 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6875 table = (xmlAttributeTablePtr) dtd->attributes;
6876 xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6877 }
6878 if ((dtd != NULL) && (dtd->entities != NULL)) {
6879 entities = (xmlEntitiesTablePtr) dtd->entities;
6880 xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6881 }
6882 dtd = doc->extSubset;
6883 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6884 table = (xmlAttributeTablePtr) dtd->attributes;
6885 xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6886 }
6887 if ((dtd != NULL) && (dtd->entities != NULL)) {
6888 entities = (xmlEntitiesTablePtr) dtd->entities;
6889 xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6890 }
6891 return(ctxt->valid);
6892}
6893
6894/**
6895 * xmlValidateDocument:
6896 * @ctxt: the validation context
6897 * @doc: a document instance
6898 *
6899 * Try to validate the document instance
6900 *
6901 * basically it does the all the checks described by the XML Rec
6902 * i.e. validates the internal and external subset (if present)
6903 * and validate the document tree.
6904 *
6905 * returns 1 if valid or 0 otherwise
6906 */
6907
6908int
6909xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6910 int ret;
6911 xmlNodePtr root;
6912
6913 if (doc == NULL)
6914 return(0);
6915 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6916 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6917 "no DTD found!\n", NULL);
6918 return(0);
6919 }
6920 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6921 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6922 xmlChar *sysID;
6923 if (doc->intSubset->SystemID != NULL) {
6924 sysID = xmlBuildURI(doc->intSubset->SystemID,
6925 doc->URL);
6926 if (sysID == NULL) {
6927 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6928 "Could not build URI for external subset \"%s\"\n",
6929 (const char *) doc->intSubset->SystemID);
6930 return 0;
6931 }
6932 } else
6933 sysID = NULL;
6934 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6935 (const xmlChar *)sysID);
6936 if (sysID != NULL)
6937 xmlFree(sysID);
6938 if (doc->extSubset == NULL) {
6939 if (doc->intSubset->SystemID != NULL) {
6940 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6941 "Could not load the external subset \"%s\"\n",
6942 (const char *) doc->intSubset->SystemID);
6943 } else {
6944 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6945 "Could not load the external subset \"%s\"\n",
6946 (const char *) doc->intSubset->ExternalID);
6947 }
6948 return(0);
6949 }
6950 }
6951
6952 if (doc->ids != NULL) {
6953 xmlFreeIDTable(doc->ids);
6954 doc->ids = NULL;
6955 }
6956 if (doc->refs != NULL) {
6957 xmlFreeRefTable(doc->refs);
6958 doc->refs = NULL;
6959 }
6960 ret = xmlValidateDtdFinal(ctxt, doc);
6961 if (!xmlValidateRoot(ctxt, doc)) return(0);
6962
6963 root = xmlDocGetRootElement(doc);
6964 ret &= xmlValidateElement(ctxt, doc, root);
6965 ret &= xmlValidateDocumentFinal(ctxt, doc);
6966 return(ret);
6967}
6968
6969/************************************************************************
6970 * *
6971 * Routines for dynamic validation editing *
6972 * *
6973 ************************************************************************/
6974
6975/**
6976 * xmlValidGetPotentialChildren:
6977 * @ctree: an element content tree
6978 * @names: an array to store the list of child names
6979 * @len: a pointer to the number of element in the list
6980 * @max: the size of the array
6981 *
6982 * Build/extend a list of potential children allowed by the content tree
6983 *
6984 * returns the number of element in the list, or -1 in case of error.
6985 */
6986
6987int
6988xmlValidGetPotentialChildren(xmlElementContent *ctree,
6989 const xmlChar **names,
6990 int *len, int max) {
6991 int i;
6992
6993 if ((ctree == NULL) || (names == NULL) || (len == NULL))
6994 return(-1);
6995 if (*len >= max) return(*len);
6996
6997 switch (ctree->type) {
6998 case XML_ELEMENT_CONTENT_PCDATA:
6999 for (i = 0; i < *len;i++)
7000 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
7001 names[(*len)++] = BAD_CAST "#PCDATA";
7002 break;
7003 case XML_ELEMENT_CONTENT_ELEMENT:
7004 for (i = 0; i < *len;i++)
7005 if (xmlStrEqual(ctree->name, names[i])) return(*len);
7006 names[(*len)++] = ctree->name;
7007 break;
7008 case XML_ELEMENT_CONTENT_SEQ:
7009 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
7010 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
7011 break;
7012 case XML_ELEMENT_CONTENT_OR:
7013 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
7014 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
7015 break;
7016 }
7017
7018 return(*len);
7019}
7020
7021/*
7022 * Dummy function to suppress messages while we try out valid elements
7023 */
7024static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
7025 const char *msg ATTRIBUTE_UNUSED, ...) {
7026 return;
7027}
7028
7029/**
7030 * xmlValidGetValidElements:
7031 * @prev: an element to insert after
7032 * @next: an element to insert next
7033 * @names: an array to store the list of child names
7034 * @max: the size of the array
7035 *
7036 * This function returns the list of authorized children to insert
7037 * within an existing tree while respecting the validity constraints
7038 * forced by the Dtd. The insertion point is defined using @prev and
7039 * @next in the following ways:
7040 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
7041 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
7042 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
7043 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
7044 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
7045 *
7046 * pointers to the element names are inserted at the beginning of the array
7047 * and do not need to be freed.
7048 *
7049 * returns the number of element in the list, or -1 in case of error. If
7050 * the function returns the value @max the caller is invited to grow the
7051 * receiving array and retry.
7052 */
7053
7054int
7055xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
7056 int max) {
7057 xmlValidCtxt vctxt;
7058 int nb_valid_elements = 0;
7059 const xmlChar *elements[256]={0};
7060 int nb_elements = 0, i;
7061 const xmlChar *name;
7062
7063 xmlNode *ref_node;
7064 xmlNode *parent;
7065 xmlNode *test_node;
7066
7067 xmlNode *prev_next;
7068 xmlNode *next_prev;
7069 xmlNode *parent_childs;
7070 xmlNode *parent_last;
7071
7072 xmlElement *element_desc;
7073
7074 if (prev == NULL && next == NULL)
7075 return(-1);
7076
7077 if (names == NULL) return(-1);
7078 if (max <= 0) return(-1);
7079
7080 memset(&vctxt, 0, sizeof (xmlValidCtxt));
7081 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
7082
7083 nb_valid_elements = 0;
7084 ref_node = prev ? prev : next;
7085 parent = ref_node->parent;
7086
7087 /*
7088 * Retrieves the parent element declaration
7089 */
7090 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
7091 parent->name);
7092 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
7093 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
7094 parent->name);
7095 if (element_desc == NULL) return(-1);
7096
7097 /*
7098 * Do a backup of the current tree structure
7099 */
7100 prev_next = prev ? prev->next : NULL;
7101 next_prev = next ? next->prev : NULL;
7102 parent_childs = parent->children;
7103 parent_last = parent->last;
7104
7105 /*
7106 * Creates a dummy node and insert it into the tree
7107 */
7108 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
7109 if (test_node == NULL)
7110 return(-1);
7111
7112 test_node->parent = parent;
7113 test_node->prev = prev;
7114 test_node->next = next;
7115 name = test_node->name;
7116
7117 if (prev) prev->next = test_node;
7118 else parent->children = test_node;
7119
7120 if (next) next->prev = test_node;
7121 else parent->last = test_node;
7122
7123 /*
7124 * Insert each potential child node and check if the parent is
7125 * still valid
7126 */
7127 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7128 elements, &nb_elements, 256);
7129
7130 for (i = 0;i < nb_elements;i++) {
7131 test_node->name = elements[i];
7132 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
7133 int j;
7134
7135 for (j = 0; j < nb_valid_elements;j++)
7136 if (xmlStrEqual(elements[i], names[j])) break;
7137 names[nb_valid_elements++] = elements[i];
7138 if (nb_valid_elements >= max) break;
7139 }
7140 }
7141
7142 /*
7143 * Restore the tree structure
7144 */
7145 if (prev) prev->next = prev_next;
7146 if (next) next->prev = next_prev;
7147 parent->children = parent_childs;
7148 parent->last = parent_last;
7149
7150 /*
7151 * Free up the dummy node
7152 */
7153 test_node->name = name;
7154 xmlFreeNode(test_node);
7155
7156 return(nb_valid_elements);
7157}
7158#endif /* LIBXML_VALID_ENABLED */
7159
7160#define bottom_valid
7161#include "elfgcchack.h"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette