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