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