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