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