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