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