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