VirtualBox

source: vbox/trunk/src/libs/libxml2-2.13.2/valid.c@ 105770

Last change on this file since 105770 was 105420, checked in by vboxsync, 4 months ago

libxml2-2.12.6: Applied and adjusted our libxml2 changes to 2.12.6. bugref:10730

  • Property svn:eol-style set to native
File size: 182.9 KB
Line 
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
32static xmlElementPtr
33xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name);
34
35#ifdef LIBXML_VALID_ENABLED
36static int
37xmlValidateAttributeValueInternal(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 */
53static void
54xmlVErrMemory(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
68static void
69xmlDoErrValid(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 */
114static void LIBXML_ATTR_FORMAT(3,0)
115xmlErrValid(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 */
134static void LIBXML_ATTR_FORMAT(4,0)
135xmlErrValidNode(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 */
157static void LIBXML_ATTR_FORMAT(4,0)
158xmlErrValidNodeNr(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 */
178static void LIBXML_ATTR_FORMAT(4,0)
179xmlErrValidWarning(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
200typedef 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
207static int
208vstateVPush(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
255static int
256vstateVPop(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
289typedef 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
311static int
312vstateVPush(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
359static int
360vstateVPop(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
374static int
375nodeVPush(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}
403static xmlNodePtr
404nodeVPop(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 */
446static int
447xmlValidBuildAContentModel(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 */
606int
607xmlValidBuildContentModel(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
653done:
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 */
675xmlValidCtxtPtr 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 */
692void
693xmlFreeValidCtxt(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 */
715xmlElementContentPtr
716xmlNewDocElementContent(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
779error:
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 */
794xmlElementContentPtr
795xmlNewElementContent(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 */
808xmlElementContentPtr
809xmlCopyDocElementContent(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
888error:
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 */
902xmlElementContentPtr
903xmlCopyElementContent(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 */
914void
915xmlFreeDocElementContent(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 */
980void
981xmlFreeElementContent(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 */
994void
995xmlSprintfElementContent(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 */
1011void
1012xmlSnprintfElementContent(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 */
1115static void
1116xmlFreeElement(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 */
1144xmlElementPtr
1145xmlAddElementDecl(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
1333mem_error:
1334 xmlVErrMemory(ctxt);
1335 if (prefix != NULL)
1336 xmlFree(prefix);
1337 return(NULL);
1338}
1339
1340static void
1341xmlFreeElementTableEntry(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 */
1351void
1352xmlFreeElementTable(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 */
1365static void *
1366xmlCopyElement(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
1395error:
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 */
1408xmlElementTablePtr
1409xmlCopyElementTable(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 */
1425void
1426xmlDumpElementDecl(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 */
1446static void
1447xmlDumpElementDeclScan(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 */
1461void
1462xmlDumpElementTable(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 */
1484xmlEnumerationPtr
1485xmlCreateEnumeration(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 */
1510void
1511xmlFreeEnumeration(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 */
1532xmlEnumerationPtr
1533xmlCopyEnumeration(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 */
1571static int
1572xmlScanIDAttributeDecl(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 */
1598static void
1599xmlFreeAttribute(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 */
1651xmlAttributePtr
1652xmlAddAttributeDecl(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
1872mem_error:
1873 xmlVErrMemory(ctxt);
1874 xmlFreeEnumeration(tree);
1875 xmlFreeAttribute(ret);
1876 return(NULL);
1877}
1878
1879static void
1880xmlFreeAttributeTableEntry(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 */
1890void
1891xmlFreeAttributeTable(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 */
1904static void *
1905xmlCopyAttribute(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
1943error:
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 */
1956xmlAttributeTablePtr
1957xmlCopyAttributeTable(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 */
1974void
1975xmlDumpAttributeDecl(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 */
1994static void
1995xmlDumpAttributeDeclScan(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 */
2009void
2010xmlDumpAttributeTable(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 */
2034static void
2035xmlFreeNotation(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 */
2059xmlNotationPtr
2060xmlAddNotationDecl(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
2131mem_error:
2132 xmlVErrMemory(ctxt);
2133 xmlFreeNotation(ret);
2134 return(NULL);
2135}
2136
2137static void
2138xmlFreeNotationTableEntry(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 */
2148void
2149xmlFreeNotationTable(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 */
2162static void *
2163xmlCopyNotation(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
2188error:
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 */
2201xmlNotationTablePtr
2202xmlCopyNotationTable(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 */
2217void
2218xmlDumpNotationDecl(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 */
2239void
2240xmlDumpNotationTable(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
2270static int
2271xmlIsStreaming(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 */
2288static void
2289xmlFreeID(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 */
2321static int
2322xmlAddIDInternal(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 /*
2340 * Create the ID table if needed.
2341 */
2342 table = (xmlIDTablePtr) doc->ids;
2343 if (table == NULL) {
2344 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2345 if (table == NULL)
2346 return(-1);
2347 } else {
2348 id = xmlHashLookup(table, value);
2349 if (id != NULL)
2350 return(0);
2351 }
2352
2353 id = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2354 if (id == NULL)
2355 return(-1);
2356 memset(id, 0, sizeof(*id));
2357
2358 /*
2359 * fill the structure.
2360 */
2361 id->doc = doc;
2362 id->value = xmlStrdup(value);
2363 if (id->value == NULL) {
2364 xmlFreeID(id);
2365 return(-1);
2366 }
2367
2368 if (attr->id != NULL)
2369 xmlRemoveID(doc, attr);
2370
2371 if (xmlHashAddEntry(table, value, id) < 0) {
2372 xmlFreeID(id);
2373 return(-1);
2374 }
2375
2376 ret = 1;
2377 if (idPtr != NULL)
2378 *idPtr = id;
2379
2380 id->attr = attr;
2381 id->lineno = xmlGetLineNo(attr->parent);
2382 attr->atype = XML_ATTRIBUTE_ID;
2383 attr->id = id;
2384
2385 return(ret);
2386}
2387
2388/**
2389 * xmlAddIDSafe:
2390 * @attr: the attribute holding the ID
2391 * @value: the attribute (ID) value
2392 *
2393 * Register a new id declaration
2394 *
2395 * Available since 2.13.0.
2396 *
2397 * Returns 1 on success, 0 if the ID already exists, -1 if a memory
2398 * allocation fails.
2399 */
2400int
2401xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value) {
2402 return(xmlAddIDInternal(attr, value, NULL));
2403}
2404
2405/**
2406 * xmlAddID:
2407 * @ctxt: the validation context
2408 * @doc: pointer to the document
2409 * @value: the value name
2410 * @attr: the attribute holding the ID
2411 *
2412 * Register a new id declaration
2413 *
2414 * Returns NULL if not, otherwise the new xmlIDPtr
2415 */
2416xmlIDPtr
2417xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2418 xmlAttrPtr attr) {
2419 xmlIDPtr id;
2420 int res;
2421
2422 if ((attr == NULL) || (doc != attr->doc))
2423 return(NULL);
2424
2425 res = xmlAddIDInternal(attr, value, &id);
2426 if (res < 0) {
2427 xmlVErrMemory(ctxt);
2428 }
2429#ifdef LIBXML_VALID_ENABLED
2430 else if (res == 0) {
2431 if (ctxt != NULL) {
2432 /*
2433 * The id is already defined in this DTD.
2434 */
2435 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2436 "ID %s already defined\n", value, NULL, NULL);
2437 }
2438 }
2439#endif /* LIBXML_VALID_ENABLED */
2440
2441 return(id);
2442}
2443
2444static void
2445xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) {
2446 xmlFreeID((xmlIDPtr) id);
2447}
2448
2449/**
2450 * xmlFreeIDTable:
2451 * @table: An id table
2452 *
2453 * Deallocate the memory used by an ID hash table.
2454 */
2455void
2456xmlFreeIDTable(xmlIDTablePtr table) {
2457 xmlHashFree(table, xmlFreeIDTableEntry);
2458}
2459
2460/**
2461 * xmlIsID:
2462 * @doc: the document
2463 * @elem: the element carrying the attribute
2464 * @attr: the attribute
2465 *
2466 * Determine whether an attribute is of type ID. In case we have DTD(s)
2467 * then this is done if DTD loading has been requested. In the case
2468 * of HTML documents parsed with the HTML parser, then ID detection is
2469 * done systematically.
2470 *
2471 * Returns 0 or 1 depending on the lookup result or -1 if a memory allocation
2472 * failed.
2473 */
2474int
2475xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2476 if ((attr == NULL) || (attr->name == NULL))
2477 return(0);
2478
2479 if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
2480 if (xmlStrEqual(BAD_CAST "id", attr->name))
2481 return(1);
2482
2483 if ((elem == NULL) || (elem->type != XML_ELEMENT_NODE))
2484 return(0);
2485
2486 if ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2487 (xmlStrEqual(elem->name, BAD_CAST "a")))
2488 return(1);
2489 } else {
2490 xmlAttributePtr attrDecl = NULL;
2491 xmlChar felem[50];
2492 xmlChar *fullelemname;
2493 const xmlChar *aprefix;
2494
2495 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2496 (!strcmp((char *) attr->name, "id")) &&
2497 (!strcmp((char *) attr->ns->prefix, "xml")))
2498 return(1);
2499
2500 if ((doc == NULL) ||
2501 ((doc->intSubset == NULL) && (doc->extSubset == NULL)))
2502 return(0);
2503
2504 if ((elem == NULL) ||
2505 (elem->type != XML_ELEMENT_NODE) ||
2506 (elem->name == NULL))
2507 return(0);
2508
2509 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2510 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2511 (xmlChar *)elem->name;
2512 if (fullelemname == NULL)
2513 return(-1);
2514
2515 aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
2516
2517 if (fullelemname != NULL) {
2518 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullelemname,
2519 attr->name, aprefix);
2520 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2521 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullelemname,
2522 attr->name, aprefix);
2523 }
2524
2525 if ((fullelemname != felem) && (fullelemname != elem->name))
2526 xmlFree(fullelemname);
2527
2528 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2529 return(1);
2530 }
2531
2532 return(0);
2533}
2534
2535/**
2536 * xmlRemoveID:
2537 * @doc: the document
2538 * @attr: the attribute
2539 *
2540 * Remove the given attribute from the ID table maintained internally.
2541 *
2542 * Returns -1 if the lookup failed and 0 otherwise
2543 */
2544int
2545xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2546 xmlIDTablePtr table;
2547
2548 if (doc == NULL) return(-1);
2549 if ((attr == NULL) || (attr->id == NULL)) return(-1);
2550
2551 table = (xmlIDTablePtr) doc->ids;
2552 if (table == NULL)
2553 return(-1);
2554
2555 if (xmlHashRemoveEntry(table, attr->id->value, xmlFreeIDTableEntry) < 0)
2556 return(-1);
2557
2558 return(0);
2559}
2560
2561/**
2562 * xmlGetID:
2563 * @doc: pointer to the document
2564 * @ID: the ID value
2565 *
2566 * Search the attribute declaring the given ID
2567 *
2568 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2569 */
2570xmlAttrPtr
2571xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2572 xmlIDTablePtr table;
2573 xmlIDPtr id;
2574
2575 if (doc == NULL) {
2576 return(NULL);
2577 }
2578
2579 if (ID == NULL) {
2580 return(NULL);
2581 }
2582
2583 table = (xmlIDTablePtr) doc->ids;
2584 if (table == NULL)
2585 return(NULL);
2586
2587 id = xmlHashLookup(table, ID);
2588 if (id == NULL)
2589 return(NULL);
2590 if (id->attr == NULL) {
2591 /*
2592 * We are operating on a stream, return a well known reference
2593 * since the attribute node doesn't exist anymore
2594 */
2595 return((xmlAttrPtr) doc);
2596 }
2597 return(id->attr);
2598}
2599
2600/************************************************************************
2601 * *
2602 * Refs *
2603 * *
2604 ************************************************************************/
2605typedef struct xmlRemoveMemo_t
2606{
2607 xmlListPtr l;
2608 xmlAttrPtr ap;
2609} xmlRemoveMemo;
2610
2611typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2612
2613typedef struct xmlValidateMemo_t
2614{
2615 xmlValidCtxtPtr ctxt;
2616 const xmlChar *name;
2617} xmlValidateMemo;
2618
2619typedef xmlValidateMemo *xmlValidateMemoPtr;
2620
2621/**
2622 * xmlFreeRef:
2623 * @lk: A list link
2624 *
2625 * Deallocate the memory used by a ref definition
2626 */
2627static void
2628xmlFreeRef(xmlLinkPtr lk) {
2629 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2630 if (ref == NULL) return;
2631 if (ref->value != NULL)
2632 xmlFree((xmlChar *)ref->value);
2633 if (ref->name != NULL)
2634 xmlFree((xmlChar *)ref->name);
2635 xmlFree(ref);
2636}
2637
2638/**
2639 * xmlFreeRefTableEntry:
2640 * @list_ref: A list of references.
2641 *
2642 * Deallocate the memory used by a list of references
2643 */
2644static void
2645xmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2646 xmlListPtr list_ref = (xmlListPtr) payload;
2647 if (list_ref == NULL) return;
2648 xmlListDelete(list_ref);
2649}
2650
2651/**
2652 * xmlWalkRemoveRef:
2653 * @data: Contents of current link
2654 * @user: Value supplied by the user
2655 *
2656 * Returns 0 to abort the walk or 1 to continue
2657 */
2658static int
2659xmlWalkRemoveRef(const void *data, void *user)
2660{
2661 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2662 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2663 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2664
2665 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2666 xmlListRemoveFirst(ref_list, (void *)data);
2667 return 0;
2668 }
2669 return 1;
2670}
2671
2672/**
2673 * xmlDummyCompare
2674 * @data0: Value supplied by the user
2675 * @data1: Value supplied by the user
2676 *
2677 * Do nothing, return 0. Used to create unordered lists.
2678 */
2679static int
2680xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2681 const void *data1 ATTRIBUTE_UNUSED)
2682{
2683 return (0);
2684}
2685
2686/**
2687 * xmlAddRef:
2688 * @ctxt: the validation context
2689 * @doc: pointer to the document
2690 * @value: the value name
2691 * @attr: the attribute holding the Ref
2692 *
2693 * DEPRECATED, do not use. This function will be removed from the public API.
2694 *
2695 * Register a new ref declaration
2696 *
2697 * Returns NULL if not, otherwise the new xmlRefPtr
2698 */
2699xmlRefPtr
2700xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2701 xmlAttrPtr attr) {
2702 xmlRefPtr ret = NULL;
2703 xmlRefTablePtr table;
2704 xmlListPtr ref_list;
2705
2706 if (doc == NULL) {
2707 return(NULL);
2708 }
2709 if (value == NULL) {
2710 return(NULL);
2711 }
2712 if (attr == NULL) {
2713 return(NULL);
2714 }
2715
2716 /*
2717 * Create the Ref table if needed.
2718 */
2719 table = (xmlRefTablePtr) doc->refs;
2720 if (table == NULL) {
2721 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2722 if (table == NULL)
2723 goto failed;
2724 }
2725
2726 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2727 if (ret == NULL)
2728 goto failed;
2729 memset(ret, 0, sizeof(*ret));
2730
2731 /*
2732 * fill the structure.
2733 */
2734 ret->value = xmlStrdup(value);
2735 if (ret->value == NULL)
2736 goto failed;
2737 if (xmlIsStreaming(ctxt)) {
2738 /*
2739 * Operating in streaming mode, attr is gonna disappear
2740 */
2741 ret->name = xmlStrdup(attr->name);
2742 if (ret->name == NULL)
2743 goto failed;
2744 ret->attr = NULL;
2745 } else {
2746 ret->name = NULL;
2747 ret->attr = attr;
2748 }
2749 ret->lineno = xmlGetLineNo(attr->parent);
2750
2751 /* To add a reference :-
2752 * References are maintained as a list of references,
2753 * Lookup the entry, if no entry create new nodelist
2754 * Add the owning node to the NodeList
2755 * Return the ref
2756 */
2757
2758 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2759 int res;
2760
2761 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare)))
2762 goto failed;
2763 res = xmlHashAdd(table, value, ref_list);
2764 if (res <= 0) {
2765 xmlListDelete(ref_list);
2766 goto failed;
2767 }
2768 }
2769 if (xmlListAppend(ref_list, ret) != 0)
2770 goto failed;
2771 return(ret);
2772
2773failed:
2774 xmlVErrMemory(ctxt);
2775 if (ret != NULL) {
2776 if (ret->value != NULL)
2777 xmlFree((char *)ret->value);
2778 if (ret->name != NULL)
2779 xmlFree((char *)ret->name);
2780 xmlFree(ret);
2781 }
2782 return(NULL);
2783}
2784
2785/**
2786 * xmlFreeRefTable:
2787 * @table: An ref table
2788 *
2789 * DEPRECATED, do not use. This function will be removed from the public API.
2790 *
2791 * Deallocate the memory used by an Ref hash table.
2792 */
2793void
2794xmlFreeRefTable(xmlRefTablePtr table) {
2795 xmlHashFree(table, xmlFreeRefTableEntry);
2796}
2797
2798/**
2799 * xmlIsRef:
2800 * @doc: the document
2801 * @elem: the element carrying the attribute
2802 * @attr: the attribute
2803 *
2804 * DEPRECATED, do not use. This function will be removed from the public API.
2805 *
2806 * Determine whether an attribute is of type Ref. In case we have DTD(s)
2807 * then this is simple, otherwise we use an heuristic: name Ref (upper
2808 * or lowercase).
2809 *
2810 * Returns 0 or 1 depending on the lookup result
2811 */
2812int
2813xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2814 if (attr == NULL)
2815 return(0);
2816 if (doc == NULL) {
2817 doc = attr->doc;
2818 if (doc == NULL) return(0);
2819 }
2820
2821 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2822 return(0);
2823 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2824 /* TODO @@@ */
2825 return(0);
2826 } else {
2827 xmlAttributePtr attrDecl;
2828 const xmlChar *aprefix;
2829
2830 if (elem == NULL) return(0);
2831 aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
2832 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, attr->name,
2833 aprefix);
2834 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2835 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, attr->name,
2836 aprefix);
2837
2838 if ((attrDecl != NULL) &&
2839 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2840 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2841 return(1);
2842 }
2843 return(0);
2844}
2845
2846/**
2847 * xmlRemoveRef:
2848 * @doc: the document
2849 * @attr: the attribute
2850 *
2851 * DEPRECATED, do not use. This function will be removed from the public API.
2852 *
2853 * Remove the given attribute from the Ref table maintained internally.
2854 *
2855 * Returns -1 if the lookup failed and 0 otherwise
2856 */
2857int
2858xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2859 xmlListPtr ref_list;
2860 xmlRefTablePtr table;
2861 xmlChar *ID;
2862 xmlRemoveMemo target;
2863
2864 if (doc == NULL) return(-1);
2865 if (attr == NULL) return(-1);
2866
2867 table = (xmlRefTablePtr) doc->refs;
2868 if (table == NULL)
2869 return(-1);
2870
2871 ID = xmlNodeListGetString(doc, attr->children, 1);
2872 if (ID == NULL)
2873 return(-1);
2874
2875 ref_list = xmlHashLookup(table, ID);
2876 if(ref_list == NULL) {
2877 xmlFree(ID);
2878 return (-1);
2879 }
2880
2881 /* At this point, ref_list refers to a list of references which
2882 * have the same key as the supplied attr. Our list of references
2883 * is ordered by reference address and we don't have that information
2884 * here to use when removing. We'll have to walk the list and
2885 * check for a matching attribute, when we find one stop the walk
2886 * and remove the entry.
2887 * The list is ordered by reference, so that means we don't have the
2888 * key. Passing the list and the reference to the walker means we
2889 * will have enough data to be able to remove the entry.
2890 */
2891 target.l = ref_list;
2892 target.ap = attr;
2893
2894 /* Remove the supplied attr from our list */
2895 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
2896
2897 /*If the list is empty then remove the list entry in the hash */
2898 if (xmlListEmpty(ref_list))
2899 xmlHashRemoveEntry(table, ID, xmlFreeRefTableEntry);
2900 xmlFree(ID);
2901 return(0);
2902}
2903
2904/**
2905 * xmlGetRefs:
2906 * @doc: pointer to the document
2907 * @ID: the ID value
2908 *
2909 * DEPRECATED, do not use. This function will be removed from the public API.
2910 *
2911 * Find the set of references for the supplied ID.
2912 *
2913 * Returns NULL if not found, otherwise node set for the ID.
2914 */
2915xmlListPtr
2916xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
2917 xmlRefTablePtr table;
2918
2919 if (doc == NULL) {
2920 return(NULL);
2921 }
2922
2923 if (ID == NULL) {
2924 return(NULL);
2925 }
2926
2927 table = (xmlRefTablePtr) doc->refs;
2928 if (table == NULL)
2929 return(NULL);
2930
2931 return (xmlHashLookup(table, ID));
2932}
2933
2934/************************************************************************
2935 * *
2936 * Routines for validity checking *
2937 * *
2938 ************************************************************************/
2939
2940/**
2941 * xmlGetDtdElementDesc:
2942 * @dtd: a pointer to the DtD to search
2943 * @name: the element name
2944 *
2945 * Search the DTD for the description of this element
2946 *
2947 * NOTE: A NULL return value can also mean that a memory allocation failed.
2948 *
2949 * returns the xmlElementPtr if found or NULL
2950 */
2951
2952xmlElementPtr
2953xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2954 xmlElementTablePtr table;
2955 xmlElementPtr cur;
2956 const xmlChar *localname;
2957 xmlChar *prefix;
2958
2959 if ((dtd == NULL) || (dtd->elements == NULL) ||
2960 (name == NULL))
2961 return(NULL);
2962
2963 table = (xmlElementTablePtr) dtd->elements;
2964 if (table == NULL)
2965 return(NULL);
2966
2967 localname = xmlSplitQName4(name, &prefix);
2968 if (localname == NULL)
2969 return(NULL);
2970 cur = xmlHashLookup2(table, localname, prefix);
2971 if (prefix != NULL)
2972 xmlFree(prefix);
2973 return(cur);
2974}
2975
2976/**
2977 * xmlGetDtdElementDesc2:
2978 * @dtd: a pointer to the DtD to search
2979 * @name: the element name
2980 * @create: create an empty description if not found
2981 *
2982 * Search the DTD for the description of this element
2983 *
2984 * returns the xmlElementPtr if found or NULL
2985 */
2986
2987static xmlElementPtr
2988xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name) {
2989 xmlElementTablePtr table;
2990 xmlElementPtr cur = NULL;
2991 const xmlChar *localName;
2992 xmlChar *prefix = NULL;
2993
2994 if (dtd == NULL) return(NULL);
2995
2996 /*
2997 * Create the Element table if needed.
2998 */
2999 if (dtd->elements == NULL) {
3000 xmlDictPtr dict = NULL;
3001
3002 if (dtd->doc != NULL)
3003 dict = dtd->doc->dict;
3004
3005 dtd->elements = xmlHashCreateDict(0, dict);
3006 if (dtd->elements == NULL)
3007 goto mem_error;
3008 }
3009 table = (xmlElementTablePtr) dtd->elements;
3010
3011 localName = xmlSplitQName4(name, &prefix);
3012 if (localName == NULL)
3013 goto mem_error;
3014 cur = xmlHashLookup2(table, localName, prefix);
3015 if (cur == NULL) {
3016 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3017 if (cur == NULL)
3018 goto mem_error;
3019 memset(cur, 0, sizeof(xmlElement));
3020 cur->type = XML_ELEMENT_DECL;
3021 cur->doc = dtd->doc;
3022
3023 /*
3024 * fill the structure.
3025 */
3026 cur->name = xmlStrdup(localName);
3027 if (cur->name == NULL)
3028 goto mem_error;
3029 cur->prefix = prefix;
3030 prefix = NULL;
3031 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3032
3033 if (xmlHashAdd2(table, localName, cur->prefix, cur) <= 0)
3034 goto mem_error;
3035 }
3036
3037 if (prefix != NULL)
3038 xmlFree(prefix);
3039 return(cur);
3040
3041mem_error:
3042 xmlVErrMemory(ctxt);
3043 xmlFree(prefix);
3044 xmlFreeElement(cur);
3045 return(NULL);
3046}
3047
3048/**
3049 * xmlGetDtdQElementDesc:
3050 * @dtd: a pointer to the DtD to search
3051 * @name: the element name
3052 * @prefix: the element namespace prefix
3053 *
3054 * Search the DTD for the description of this element
3055 *
3056 * returns the xmlElementPtr if found or NULL
3057 */
3058
3059xmlElementPtr
3060xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3061 const xmlChar *prefix) {
3062 xmlElementTablePtr table;
3063
3064 if (dtd == NULL) return(NULL);
3065 if (dtd->elements == NULL) return(NULL);
3066 table = (xmlElementTablePtr) dtd->elements;
3067
3068 return(xmlHashLookup2(table, name, prefix));
3069}
3070
3071/**
3072 * xmlGetDtdAttrDesc:
3073 * @dtd: a pointer to the DtD to search
3074 * @elem: the element name
3075 * @name: the attribute name
3076 *
3077 * Search the DTD for the description of this attribute on
3078 * this element.
3079 *
3080 * returns the xmlAttributePtr if found or NULL
3081 */
3082
3083xmlAttributePtr
3084xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3085 xmlAttributeTablePtr table;
3086 xmlAttributePtr cur;
3087 const xmlChar *localname;
3088 xmlChar *prefix = NULL;
3089
3090 if ((dtd == NULL) || (dtd->attributes == NULL) ||
3091 (elem == NULL) || (name == NULL))
3092 return(NULL);
3093
3094 table = (xmlAttributeTablePtr) dtd->attributes;
3095 if (table == NULL)
3096 return(NULL);
3097
3098 localname = xmlSplitQName4(name, &prefix);
3099 if (localname == NULL)
3100 return(NULL);
3101 cur = xmlHashLookup3(table, localname, prefix, elem);
3102 if (prefix != NULL)
3103 xmlFree(prefix);
3104 return(cur);
3105}
3106
3107/**
3108 * xmlGetDtdQAttrDesc:
3109 * @dtd: a pointer to the DtD to search
3110 * @elem: the element name
3111 * @name: the attribute name
3112 * @prefix: the attribute namespace prefix
3113 *
3114 * Search the DTD for the description of this qualified attribute on
3115 * this element.
3116 *
3117 * returns the xmlAttributePtr if found or NULL
3118 */
3119
3120xmlAttributePtr
3121xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3122 const xmlChar *prefix) {
3123 xmlAttributeTablePtr table;
3124
3125 if (dtd == NULL) return(NULL);
3126 if (dtd->attributes == NULL) return(NULL);
3127 table = (xmlAttributeTablePtr) dtd->attributes;
3128
3129 return(xmlHashLookup3(table, name, prefix, elem));
3130}
3131
3132/**
3133 * xmlGetDtdNotationDesc:
3134 * @dtd: a pointer to the DtD to search
3135 * @name: the notation name
3136 *
3137 * Search the DTD for the description of this notation
3138 *
3139 * returns the xmlNotationPtr if found or NULL
3140 */
3141
3142xmlNotationPtr
3143xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3144 xmlNotationTablePtr table;
3145
3146 if (dtd == NULL) return(NULL);
3147 if (dtd->notations == NULL) return(NULL);
3148 table = (xmlNotationTablePtr) dtd->notations;
3149
3150 return(xmlHashLookup(table, name));
3151}
3152
3153#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3154/**
3155 * xmlValidateNotationUse:
3156 * @ctxt: the validation context
3157 * @doc: the document
3158 * @notationName: the notation name to check
3159 *
3160 * DEPRECATED: Internal function, don't use.
3161 *
3162 * Validate that the given name match a notation declaration.
3163 * - [ VC: Notation Declared ]
3164 *
3165 * returns 1 if valid or 0 otherwise
3166 */
3167
3168int
3169xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3170 const xmlChar *notationName) {
3171 xmlNotationPtr notaDecl;
3172 if ((doc == NULL) || (doc->intSubset == NULL) ||
3173 (notationName == NULL)) return(-1);
3174
3175 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3176 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3177 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3178
3179 if ((notaDecl == NULL) && (ctxt != NULL)) {
3180 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3181 "NOTATION %s is not declared\n",
3182 notationName, NULL, NULL);
3183 return(0);
3184 }
3185 return(1);
3186}
3187#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3188
3189/**
3190 * xmlIsMixedElement:
3191 * @doc: the document
3192 * @name: the element name
3193 *
3194 * Search in the DtDs whether an element accept Mixed content (or ANY)
3195 * basically if it is supposed to accept text childs
3196 *
3197 * returns 0 if no, 1 if yes, and -1 if no element description is available
3198 */
3199
3200int
3201xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3202 xmlElementPtr elemDecl;
3203
3204 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3205
3206 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3207 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3208 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3209 if (elemDecl == NULL) return(-1);
3210 switch (elemDecl->etype) {
3211 case XML_ELEMENT_TYPE_UNDEFINED:
3212 return(-1);
3213 case XML_ELEMENT_TYPE_ELEMENT:
3214 return(0);
3215 case XML_ELEMENT_TYPE_EMPTY:
3216 /*
3217 * return 1 for EMPTY since we want VC error to pop up
3218 * on <empty> </empty> for example
3219 */
3220 case XML_ELEMENT_TYPE_ANY:
3221 case XML_ELEMENT_TYPE_MIXED:
3222 return(1);
3223 }
3224 return(1);
3225}
3226
3227#ifdef LIBXML_VALID_ENABLED
3228
3229/**
3230 * xmlValidNormalizeString:
3231 * @str: a string
3232 *
3233 * Normalize a string in-place.
3234 */
3235static void
3236xmlValidNormalizeString(xmlChar *str) {
3237 xmlChar *dst;
3238 const xmlChar *src;
3239
3240 if (str == NULL)
3241 return;
3242 src = str;
3243 dst = str;
3244
3245 while (*src == 0x20) src++;
3246 while (*src != 0) {
3247 if (*src == 0x20) {
3248 while (*src == 0x20) src++;
3249 if (*src != 0)
3250 *dst++ = 0x20;
3251 } else {
3252 *dst++ = *src++;
3253 }
3254 }
3255 *dst = 0;
3256}
3257
3258static int
3259xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3260 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3261 /*
3262 * Use the new checks of production [4] [4a] amd [5] of the
3263 * Update 5 of XML-1.0
3264 */
3265 if (((c >= 'a') && (c <= 'z')) ||
3266 ((c >= 'A') && (c <= 'Z')) ||
3267 (c == '_') || (c == ':') ||
3268 ((c >= 0xC0) && (c <= 0xD6)) ||
3269 ((c >= 0xD8) && (c <= 0xF6)) ||
3270 ((c >= 0xF8) && (c <= 0x2FF)) ||
3271 ((c >= 0x370) && (c <= 0x37D)) ||
3272 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3273 ((c >= 0x200C) && (c <= 0x200D)) ||
3274 ((c >= 0x2070) && (c <= 0x218F)) ||
3275 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3276 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3277 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3278 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3279 ((c >= 0x10000) && (c <= 0xEFFFF)))
3280 return(1);
3281 } else {
3282 if (IS_LETTER(c) || (c == '_') || (c == ':'))
3283 return(1);
3284 }
3285 return(0);
3286}
3287
3288static int
3289xmlIsDocNameChar(xmlDocPtr doc, int c) {
3290 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3291 /*
3292 * Use the new checks of production [4] [4a] amd [5] of the
3293 * Update 5 of XML-1.0
3294 */
3295 if (((c >= 'a') && (c <= 'z')) ||
3296 ((c >= 'A') && (c <= 'Z')) ||
3297 ((c >= '0') && (c <= '9')) || /* !start */
3298 (c == '_') || (c == ':') ||
3299 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3300 ((c >= 0xC0) && (c <= 0xD6)) ||
3301 ((c >= 0xD8) && (c <= 0xF6)) ||
3302 ((c >= 0xF8) && (c <= 0x2FF)) ||
3303 ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3304 ((c >= 0x370) && (c <= 0x37D)) ||
3305 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3306 ((c >= 0x200C) && (c <= 0x200D)) ||
3307 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3308 ((c >= 0x2070) && (c <= 0x218F)) ||
3309 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3310 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3311 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3312 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3313 ((c >= 0x10000) && (c <= 0xEFFFF)))
3314 return(1);
3315 } else {
3316 if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3317 (c == '.') || (c == '-') ||
3318 (c == '_') || (c == ':') ||
3319 (IS_COMBINING(c)) ||
3320 (IS_EXTENDER(c)))
3321 return(1);
3322 }
3323 return(0);
3324}
3325
3326/**
3327 * xmlValidateNameValue:
3328 * @doc: pointer to the document or NULL
3329 * @value: an Name value
3330 *
3331 * Validate that the given value match Name production
3332 *
3333 * returns 1 if valid or 0 otherwise
3334 */
3335
3336static int
3337xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3338 const xmlChar *cur;
3339 int val, len;
3340
3341 if (value == NULL) return(0);
3342 cur = value;
3343 val = xmlStringCurrentChar(NULL, cur, &len);
3344 cur += len;
3345 if (!xmlIsDocNameStartChar(doc, val))
3346 return(0);
3347
3348 val = xmlStringCurrentChar(NULL, cur, &len);
3349 cur += len;
3350 while (xmlIsDocNameChar(doc, val)) {
3351 val = xmlStringCurrentChar(NULL, cur, &len);
3352 cur += len;
3353 }
3354
3355 if (val != 0) return(0);
3356
3357 return(1);
3358}
3359
3360/**
3361 * xmlValidateNameValue:
3362 * @value: an Name value
3363 *
3364 * Validate that the given value match Name production
3365 *
3366 * returns 1 if valid or 0 otherwise
3367 */
3368
3369int
3370xmlValidateNameValue(const xmlChar *value) {
3371 return(xmlValidateNameValueInternal(NULL, value));
3372}
3373
3374/**
3375 * xmlValidateNamesValueInternal:
3376 * @doc: pointer to the document or NULL
3377 * @value: an Names value
3378 *
3379 * Validate that the given value match Names production
3380 *
3381 * returns 1 if valid or 0 otherwise
3382 */
3383
3384static int
3385xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3386 const xmlChar *cur;
3387 int val, len;
3388
3389 if (value == NULL) return(0);
3390 cur = value;
3391 val = xmlStringCurrentChar(NULL, cur, &len);
3392 cur += len;
3393
3394 if (!xmlIsDocNameStartChar(doc, val))
3395 return(0);
3396
3397 val = xmlStringCurrentChar(NULL, cur, &len);
3398 cur += len;
3399 while (xmlIsDocNameChar(doc, val)) {
3400 val = xmlStringCurrentChar(NULL, cur, &len);
3401 cur += len;
3402 }
3403
3404 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3405 while (val == 0x20) {
3406 while (val == 0x20) {
3407 val = xmlStringCurrentChar(NULL, cur, &len);
3408 cur += len;
3409 }
3410
3411 if (!xmlIsDocNameStartChar(doc, val))
3412 return(0);
3413
3414 val = xmlStringCurrentChar(NULL, cur, &len);
3415 cur += len;
3416
3417 while (xmlIsDocNameChar(doc, val)) {
3418 val = xmlStringCurrentChar(NULL, cur, &len);
3419 cur += len;
3420 }
3421 }
3422
3423 if (val != 0) return(0);
3424
3425 return(1);
3426}
3427
3428/**
3429 * xmlValidateNamesValue:
3430 * @value: an Names value
3431 *
3432 * Validate that the given value match Names production
3433 *
3434 * returns 1 if valid or 0 otherwise
3435 */
3436
3437int
3438xmlValidateNamesValue(const xmlChar *value) {
3439 return(xmlValidateNamesValueInternal(NULL, value));
3440}
3441
3442/**
3443 * xmlValidateNmtokenValueInternal:
3444 * @doc: pointer to the document or NULL
3445 * @value: an Nmtoken value
3446 *
3447 * Validate that the given value match Nmtoken production
3448 *
3449 * [ VC: Name Token ]
3450 *
3451 * returns 1 if valid or 0 otherwise
3452 */
3453
3454static int
3455xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3456 const xmlChar *cur;
3457 int val, len;
3458
3459 if (value == NULL) return(0);
3460 cur = value;
3461 val = xmlStringCurrentChar(NULL, cur, &len);
3462 cur += len;
3463
3464 if (!xmlIsDocNameChar(doc, val))
3465 return(0);
3466
3467 val = xmlStringCurrentChar(NULL, cur, &len);
3468 cur += len;
3469 while (xmlIsDocNameChar(doc, val)) {
3470 val = xmlStringCurrentChar(NULL, cur, &len);
3471 cur += len;
3472 }
3473
3474 if (val != 0) return(0);
3475
3476 return(1);
3477}
3478
3479/**
3480 * xmlValidateNmtokenValue:
3481 * @value: an Nmtoken value
3482 *
3483 * Validate that the given value match Nmtoken production
3484 *
3485 * [ VC: Name Token ]
3486 *
3487 * returns 1 if valid or 0 otherwise
3488 */
3489
3490int
3491xmlValidateNmtokenValue(const xmlChar *value) {
3492 return(xmlValidateNmtokenValueInternal(NULL, value));
3493}
3494
3495/**
3496 * xmlValidateNmtokensValueInternal:
3497 * @doc: pointer to the document or NULL
3498 * @value: an Nmtokens value
3499 *
3500 * Validate that the given value match Nmtokens production
3501 *
3502 * [ VC: Name Token ]
3503 *
3504 * returns 1 if valid or 0 otherwise
3505 */
3506
3507static int
3508xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3509 const xmlChar *cur;
3510 int val, len;
3511
3512 if (value == NULL) return(0);
3513 cur = value;
3514 val = xmlStringCurrentChar(NULL, cur, &len);
3515 cur += len;
3516
3517 while (IS_BLANK(val)) {
3518 val = xmlStringCurrentChar(NULL, cur, &len);
3519 cur += len;
3520 }
3521
3522 if (!xmlIsDocNameChar(doc, val))
3523 return(0);
3524
3525 while (xmlIsDocNameChar(doc, val)) {
3526 val = xmlStringCurrentChar(NULL, cur, &len);
3527 cur += len;
3528 }
3529
3530 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3531 while (val == 0x20) {
3532 while (val == 0x20) {
3533 val = xmlStringCurrentChar(NULL, cur, &len);
3534 cur += len;
3535 }
3536 if (val == 0) return(1);
3537
3538 if (!xmlIsDocNameChar(doc, val))
3539 return(0);
3540
3541 val = xmlStringCurrentChar(NULL, cur, &len);
3542 cur += len;
3543
3544 while (xmlIsDocNameChar(doc, val)) {
3545 val = xmlStringCurrentChar(NULL, cur, &len);
3546 cur += len;
3547 }
3548 }
3549
3550 if (val != 0) return(0);
3551
3552 return(1);
3553}
3554
3555/**
3556 * xmlValidateNmtokensValue:
3557 * @value: an Nmtokens value
3558 *
3559 * Validate that the given value match Nmtokens production
3560 *
3561 * [ VC: Name Token ]
3562 *
3563 * returns 1 if valid or 0 otherwise
3564 */
3565
3566int
3567xmlValidateNmtokensValue(const xmlChar *value) {
3568 return(xmlValidateNmtokensValueInternal(NULL, value));
3569}
3570
3571/**
3572 * xmlValidateNotationDecl:
3573 * @ctxt: the validation context
3574 * @doc: a document instance
3575 * @nota: a notation definition
3576 *
3577 * DEPRECATED: Internal function, don't use.
3578 *
3579 * Try to validate a single notation definition
3580 * basically it does the following checks as described by the
3581 * XML-1.0 recommendation:
3582 * - it seems that no validity constraint exists on notation declarations
3583 * But this function get called anyway ...
3584 *
3585 * returns 1 if valid or 0 otherwise
3586 */
3587
3588int
3589xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3590 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3591 int ret = 1;
3592
3593 return(ret);
3594}
3595
3596/**
3597 * xmlValidateAttributeValueInternal:
3598 * @doc: the document
3599 * @type: an attribute type
3600 * @value: an attribute value
3601 *
3602 * Validate that the given attribute value match the proper production
3603 *
3604 * returns 1 if valid or 0 otherwise
3605 */
3606
3607static int
3608xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3609 const xmlChar *value) {
3610 switch (type) {
3611 case XML_ATTRIBUTE_ENTITIES:
3612 case XML_ATTRIBUTE_IDREFS:
3613 return(xmlValidateNamesValueInternal(doc, value));
3614 case XML_ATTRIBUTE_ENTITY:
3615 case XML_ATTRIBUTE_IDREF:
3616 case XML_ATTRIBUTE_ID:
3617 case XML_ATTRIBUTE_NOTATION:
3618 return(xmlValidateNameValueInternal(doc, value));
3619 case XML_ATTRIBUTE_NMTOKENS:
3620 case XML_ATTRIBUTE_ENUMERATION:
3621 return(xmlValidateNmtokensValueInternal(doc, value));
3622 case XML_ATTRIBUTE_NMTOKEN:
3623 return(xmlValidateNmtokenValueInternal(doc, value));
3624 case XML_ATTRIBUTE_CDATA:
3625 break;
3626 }
3627 return(1);
3628}
3629
3630/**
3631 * xmlValidateAttributeValue:
3632 * @type: an attribute type
3633 * @value: an attribute value
3634 *
3635 * DEPRECATED: Internal function, don't use.
3636 *
3637 * Validate that the given attribute value match the proper production
3638 *
3639 * [ VC: ID ]
3640 * Values of type ID must match the Name production....
3641 *
3642 * [ VC: IDREF ]
3643 * Values of type IDREF must match the Name production, and values
3644 * of type IDREFS must match Names ...
3645 *
3646 * [ VC: Entity Name ]
3647 * Values of type ENTITY must match the Name production, values
3648 * of type ENTITIES must match Names ...
3649 *
3650 * [ VC: Name Token ]
3651 * Values of type NMTOKEN must match the Nmtoken production; values
3652 * of type NMTOKENS must match Nmtokens.
3653 *
3654 * returns 1 if valid or 0 otherwise
3655 */
3656int
3657xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3658 return(xmlValidateAttributeValueInternal(NULL, type, value));
3659}
3660
3661/**
3662 * xmlValidateAttributeValue2:
3663 * @ctxt: the validation context
3664 * @doc: the document
3665 * @name: the attribute name (used for error reporting only)
3666 * @type: the attribute type
3667 * @value: the attribute value
3668 *
3669 * Validate that the given attribute value match a given type.
3670 * This typically cannot be done before having finished parsing
3671 * the subsets.
3672 *
3673 * [ VC: IDREF ]
3674 * Values of type IDREF must match one of the declared IDs
3675 * Values of type IDREFS must match a sequence of the declared IDs
3676 * each Name must match the value of an ID attribute on some element
3677 * in the XML document; i.e. IDREF values must match the value of
3678 * some ID attribute
3679 *
3680 * [ VC: Entity Name ]
3681 * Values of type ENTITY must match one declared entity
3682 * Values of type ENTITIES must match a sequence of declared entities
3683 *
3684 * [ VC: Notation Attributes ]
3685 * all notation names in the declaration must be declared.
3686 *
3687 * returns 1 if valid or 0 otherwise
3688 */
3689
3690static int
3691xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3692 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3693 int ret = 1;
3694 switch (type) {
3695 case XML_ATTRIBUTE_IDREFS:
3696 case XML_ATTRIBUTE_IDREF:
3697 case XML_ATTRIBUTE_ID:
3698 case XML_ATTRIBUTE_NMTOKENS:
3699 case XML_ATTRIBUTE_ENUMERATION:
3700 case XML_ATTRIBUTE_NMTOKEN:
3701 case XML_ATTRIBUTE_CDATA:
3702 break;
3703 case XML_ATTRIBUTE_ENTITY: {
3704 xmlEntityPtr ent;
3705
3706 ent = xmlGetDocEntity(doc, value);
3707 /* yeah it's a bit messy... */
3708 if ((ent == NULL) && (doc->standalone == 1)) {
3709 doc->standalone = 0;
3710 ent = xmlGetDocEntity(doc, value);
3711 }
3712 if (ent == NULL) {
3713 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3714 XML_DTD_UNKNOWN_ENTITY,
3715 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3716 name, value, NULL);
3717 ret = 0;
3718 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3719 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3720 XML_DTD_ENTITY_TYPE,
3721 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3722 name, value, NULL);
3723 ret = 0;
3724 }
3725 break;
3726 }
3727 case XML_ATTRIBUTE_ENTITIES: {
3728 xmlChar *dup, *nam = NULL, *cur, save;
3729 xmlEntityPtr ent;
3730
3731 dup = xmlStrdup(value);
3732 if (dup == NULL) {
3733 xmlVErrMemory(ctxt);
3734 return(0);
3735 }
3736 cur = dup;
3737 while (*cur != 0) {
3738 nam = cur;
3739 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
3740 save = *cur;
3741 *cur = 0;
3742 ent = xmlGetDocEntity(doc, nam);
3743 if (ent == NULL) {
3744 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3745 XML_DTD_UNKNOWN_ENTITY,
3746 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3747 name, nam, NULL);
3748 ret = 0;
3749 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3750 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3751 XML_DTD_ENTITY_TYPE,
3752 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3753 name, nam, NULL);
3754 ret = 0;
3755 }
3756 if (save == 0)
3757 break;
3758 *cur = save;
3759 while (IS_BLANK_CH(*cur)) cur++;
3760 }
3761 xmlFree(dup);
3762 break;
3763 }
3764 case XML_ATTRIBUTE_NOTATION: {
3765 xmlNotationPtr nota;
3766
3767 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3768 if ((nota == NULL) && (doc->extSubset != NULL))
3769 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3770
3771 if (nota == NULL) {
3772 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3773 XML_DTD_UNKNOWN_NOTATION,
3774 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3775 name, value, NULL);
3776 ret = 0;
3777 }
3778 break;
3779 }
3780 }
3781 return(ret);
3782}
3783
3784/**
3785 * xmlValidCtxtNormalizeAttributeValue:
3786 * @ctxt: the validation context
3787 * @doc: the document
3788 * @elem: the parent
3789 * @name: the attribute name
3790 * @value: the attribute value
3791 * @ctxt: the validation context or NULL
3792 *
3793 * DEPRECATED: Internal function, don't use.
3794 *
3795 * Does the validation related extra step of the normalization of attribute
3796 * values:
3797 *
3798 * If the declared value is not CDATA, then the XML processor must further
3799 * process the normalized attribute value by discarding any leading and
3800 * trailing space (#x20) characters, and by replacing sequences of space
3801 * (#x20) characters by single space (#x20) character.
3802 *
3803 * Also check VC: Standalone Document Declaration in P32, and update
3804 * ctxt->valid accordingly
3805 *
3806 * returns a new normalized string if normalization is needed, NULL otherwise
3807 * the caller must free the returned value.
3808 */
3809
3810xmlChar *
3811xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3812 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3813 xmlChar *ret;
3814 xmlAttributePtr attrDecl = NULL;
3815 const xmlChar *localName;
3816 xmlChar *prefix = NULL;
3817 int extsubset = 0;
3818
3819 if (doc == NULL) return(NULL);
3820 if (elem == NULL) return(NULL);
3821 if (name == NULL) return(NULL);
3822 if (value == NULL) return(NULL);
3823
3824 localName = xmlSplitQName4(name, &prefix);
3825 if (localName == NULL)
3826 goto mem_error;
3827
3828 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3829 xmlChar buf[50];
3830 xmlChar *elemname;
3831
3832 elemname = xmlBuildQName(elem->name, elem->ns->prefix, buf, 50);
3833 if (elemname == NULL)
3834 goto mem_error;
3835 if (doc->intSubset != NULL)
3836 attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName,
3837 prefix, elemname);
3838 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3839 attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName,
3840 prefix, elemname);
3841 if (attrDecl != NULL)
3842 extsubset = 1;
3843 }
3844 if ((elemname != buf) && (elemname != elem->name))
3845 xmlFree(elemname);
3846 }
3847 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3848 attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName,
3849 prefix, elem->name);
3850 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3851 attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName,
3852 prefix, elem->name);
3853 if (attrDecl != NULL)
3854 extsubset = 1;
3855 }
3856
3857 if (attrDecl == NULL)
3858 goto done;
3859 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3860 goto done;
3861
3862 ret = xmlStrdup(value);
3863 if (ret == NULL)
3864 goto mem_error;
3865 xmlValidNormalizeString(ret);
3866 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
3867 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
3868"standalone: %s on %s value had to be normalized based on external subset declaration\n",
3869 name, elem->name, NULL);
3870 ctxt->valid = 0;
3871 }
3872
3873 xmlFree(prefix);
3874 return(ret);
3875
3876mem_error:
3877 xmlVErrMemory(ctxt);
3878
3879done:
3880 xmlFree(prefix);
3881 return(NULL);
3882}
3883
3884/**
3885 * xmlValidNormalizeAttributeValue:
3886 * @doc: the document
3887 * @elem: the parent
3888 * @name: the attribute name
3889 * @value: the attribute value
3890 *
3891 * DEPRECATED: Internal function, don't use.
3892 *
3893 * Does the validation related extra step of the normalization of attribute
3894 * values:
3895 *
3896 * If the declared value is not CDATA, then the XML processor must further
3897 * process the normalized attribute value by discarding any leading and
3898 * trailing space (#x20) characters, and by replacing sequences of space
3899 * (#x20) characters by single space (#x20) character.
3900 *
3901 * Returns a new normalized string if normalization is needed, NULL otherwise
3902 * the caller must free the returned value.
3903 */
3904
3905xmlChar *
3906xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3907 const xmlChar *name, const xmlChar *value) {
3908 xmlChar *ret;
3909 xmlAttributePtr attrDecl = NULL;
3910
3911 if (doc == NULL) return(NULL);
3912 if (elem == NULL) return(NULL);
3913 if (name == NULL) return(NULL);
3914 if (value == NULL) return(NULL);
3915
3916 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3917 xmlChar fn[50];
3918 xmlChar *fullname;
3919
3920 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3921 if (fullname == NULL)
3922 return(NULL);
3923 if ((fullname != fn) && (fullname != elem->name))
3924 xmlFree(fullname);
3925 }
3926 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3927 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3928 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3929
3930 if (attrDecl == NULL)
3931 return(NULL);
3932 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3933 return(NULL);
3934
3935 ret = xmlStrdup(value);
3936 if (ret == NULL)
3937 return(NULL);
3938 xmlValidNormalizeString(ret);
3939 return(ret);
3940}
3941
3942static void
3943xmlValidateAttributeIdCallback(void *payload, void *data,
3944 const xmlChar *name ATTRIBUTE_UNUSED) {
3945 xmlAttributePtr attr = (xmlAttributePtr) payload;
3946 int *count = (int *) data;
3947 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3948}
3949
3950/**
3951 * xmlValidateAttributeDecl:
3952 * @ctxt: the validation context
3953 * @doc: a document instance
3954 * @attr: an attribute definition
3955 *
3956 * DEPRECATED: Internal function, don't use.
3957 *
3958 * Try to validate a single attribute definition
3959 * basically it does the following checks as described by the
3960 * XML-1.0 recommendation:
3961 * - [ VC: Attribute Default Legal ]
3962 * - [ VC: Enumeration ]
3963 * - [ VC: ID Attribute Default ]
3964 *
3965 * The ID/IDREF uniqueness and matching are done separately
3966 *
3967 * returns 1 if valid or 0 otherwise
3968 */
3969
3970int
3971xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3972 xmlAttributePtr attr) {
3973 int ret = 1;
3974 int val;
3975 CHECK_DTD;
3976 if(attr == NULL) return(1);
3977
3978 /* Attribute Default Legal */
3979 /* Enumeration */
3980 if (attr->defaultValue != NULL) {
3981 val = xmlValidateAttributeValueInternal(doc, attr->atype,
3982 attr->defaultValue);
3983 if (val == 0) {
3984 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
3985 "Syntax of default value for attribute %s of %s is not valid\n",
3986 attr->name, attr->elem, NULL);
3987 }
3988 ret &= val;
3989 }
3990
3991 /* ID Attribute Default */
3992 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3993 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3994 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
3995 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
3996 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
3997 attr->name, attr->elem, NULL);
3998 ret = 0;
3999 }
4000
4001 /* One ID per Element Type */
4002 if (attr->atype == XML_ATTRIBUTE_ID) {
4003 xmlElementPtr elem = NULL;
4004 const xmlChar *elemLocalName;
4005 xmlChar *elemPrefix;
4006 int nbId;
4007
4008 elemLocalName = xmlSplitQName4(attr->elem, &elemPrefix);
4009 if (elemLocalName == NULL) {
4010 xmlVErrMemory(ctxt);
4011 return(0);
4012 }
4013
4014 /* the trick is that we parse DtD as their own internal subset */
4015 if (doc->intSubset != NULL)
4016 elem = xmlHashLookup2(doc->intSubset->elements,
4017 elemLocalName, elemPrefix);
4018 if (elem != NULL) {
4019 nbId = xmlScanIDAttributeDecl(ctxt, elem, 0);
4020 } else {
4021 xmlAttributeTablePtr table;
4022
4023 /*
4024 * The attribute may be declared in the internal subset and the
4025 * element in the external subset.
4026 */
4027 nbId = 0;
4028 if (doc->intSubset != NULL) {
4029 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4030 xmlHashScan3(table, NULL, NULL, attr->elem,
4031 xmlValidateAttributeIdCallback, &nbId);
4032 }
4033 }
4034 if (nbId > 1) {
4035
4036 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4037 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4038 attr->elem, nbId, attr->name);
4039 ret = 0;
4040 } else if (doc->extSubset != NULL) {
4041 int extId = 0;
4042 elem = xmlHashLookup2(doc->extSubset->elements,
4043 elemLocalName, elemPrefix);
4044 if (elem != NULL) {
4045 extId = xmlScanIDAttributeDecl(ctxt, elem, 0);
4046 }
4047 if (extId > 1) {
4048 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4049 "Element %s has %d ID attribute defined in the external subset : %s\n",
4050 attr->elem, extId, attr->name);
4051 ret = 0;
4052 } else if (extId + nbId > 1) {
4053 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4054"Element %s has ID attributes defined in the internal and external subset : %s\n",
4055 attr->elem, attr->name, NULL);
4056 ret = 0;
4057 }
4058 }
4059
4060 xmlFree(elemPrefix);
4061 }
4062
4063 /* Validity Constraint: Enumeration */
4064 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4065 xmlEnumerationPtr tree = attr->tree;
4066 while (tree != NULL) {
4067 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4068 tree = tree->next;
4069 }
4070 if (tree == NULL) {
4071 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4072"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4073 attr->defaultValue, attr->name, attr->elem);
4074 ret = 0;
4075 }
4076 }
4077
4078 return(ret);
4079}
4080
4081/**
4082 * xmlValidateElementDecl:
4083 * @ctxt: the validation context
4084 * @doc: a document instance
4085 * @elem: an element definition
4086 *
4087 * DEPRECATED: Internal function, don't use.
4088 *
4089 * Try to validate a single element definition
4090 * basically it does the following checks as described by the
4091 * XML-1.0 recommendation:
4092 * - [ VC: One ID per Element Type ]
4093 * - [ VC: No Duplicate Types ]
4094 * - [ VC: Unique Element Type Declaration ]
4095 *
4096 * returns 1 if valid or 0 otherwise
4097 */
4098
4099int
4100xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4101 xmlElementPtr elem) {
4102 int ret = 1;
4103 xmlElementPtr tst;
4104 const xmlChar *localName;
4105 xmlChar *prefix;
4106
4107 CHECK_DTD;
4108
4109 if (elem == NULL) return(1);
4110
4111#if 0
4112#ifdef LIBXML_REGEXP_ENABLED
4113 /* Build the regexp associated to the content model */
4114 ret = xmlValidBuildContentModel(ctxt, elem);
4115#endif
4116#endif
4117
4118 /* No Duplicate Types */
4119 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4120 xmlElementContentPtr cur, next;
4121 const xmlChar *name;
4122
4123 cur = elem->content;
4124 while (cur != NULL) {
4125 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4126 if (cur->c1 == NULL) break;
4127 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4128 name = cur->c1->name;
4129 next = cur->c2;
4130 while (next != NULL) {
4131 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4132 if ((xmlStrEqual(next->name, name)) &&
4133 (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4134 if (cur->c1->prefix == NULL) {
4135 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4136 "Definition of %s has duplicate references of %s\n",
4137 elem->name, name, NULL);
4138 } else {
4139 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4140 "Definition of %s has duplicate references of %s:%s\n",
4141 elem->name, cur->c1->prefix, name);
4142 }
4143 ret = 0;
4144 }
4145 break;
4146 }
4147 if (next->c1 == NULL) break;
4148 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4149 if ((xmlStrEqual(next->c1->name, name)) &&
4150 (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4151 if (cur->c1->prefix == NULL) {
4152 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4153 "Definition of %s has duplicate references to %s\n",
4154 elem->name, name, NULL);
4155 } else {
4156 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4157 "Definition of %s has duplicate references to %s:%s\n",
4158 elem->name, cur->c1->prefix, name);
4159 }
4160 ret = 0;
4161 }
4162 next = next->c2;
4163 }
4164 }
4165 cur = cur->c2;
4166 }
4167 }
4168
4169 localName = xmlSplitQName4(elem->name, &prefix);
4170 if (localName == NULL) {
4171 xmlVErrMemory(ctxt);
4172 return(0);
4173 }
4174
4175 /* VC: Unique Element Type Declaration */
4176 if (doc->intSubset != NULL) {
4177 tst = xmlHashLookup2(doc->intSubset->elements, localName, prefix);
4178
4179 if ((tst != NULL ) && (tst != elem) &&
4180 ((tst->prefix == elem->prefix) ||
4181 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4182 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4183 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4184 "Redefinition of element %s\n",
4185 elem->name, NULL, NULL);
4186 ret = 0;
4187 }
4188 }
4189 if (doc->extSubset != NULL) {
4190 tst = xmlHashLookup2(doc->extSubset->elements, localName, prefix);
4191
4192 if ((tst != NULL ) && (tst != elem) &&
4193 ((tst->prefix == elem->prefix) ||
4194 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4195 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4196 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4197 "Redefinition of element %s\n",
4198 elem->name, NULL, NULL);
4199 ret = 0;
4200 }
4201 }
4202
4203 /* One ID per Element Type
4204 * already done when registering the attribute
4205 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4206 ret = 0;
4207 } */
4208
4209 xmlFree(prefix);
4210 return(ret);
4211}
4212
4213/**
4214 * xmlValidateOneAttribute:
4215 * @ctxt: the validation context
4216 * @doc: a document instance
4217 * @elem: an element instance
4218 * @attr: an attribute instance
4219 * @value: the attribute value (without entities processing)
4220 *
4221 * DEPRECATED: Internal function, don't use.
4222 *
4223 * Try to validate a single attribute for an element
4224 * basically it does the following checks as described by the
4225 * XML-1.0 recommendation:
4226 * - [ VC: Attribute Value Type ]
4227 * - [ VC: Fixed Attribute Default ]
4228 * - [ VC: Entity Name ]
4229 * - [ VC: Name Token ]
4230 * - [ VC: ID ]
4231 * - [ VC: IDREF ]
4232 * - [ VC: Entity Name ]
4233 * - [ VC: Notation Attributes ]
4234 *
4235 * The ID/IDREF uniqueness and matching are done separately
4236 *
4237 * returns 1 if valid or 0 otherwise
4238 */
4239
4240int
4241xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4242 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4243{
4244 xmlAttributePtr attrDecl = NULL;
4245 const xmlChar *aprefix;
4246 int val;
4247 int ret = 1;
4248
4249 CHECK_DTD;
4250 if ((elem == NULL) || (elem->name == NULL)) return(0);
4251 if ((attr == NULL) || (attr->name == NULL)) return(0);
4252
4253 aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
4254
4255 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4256 xmlChar fn[50];
4257 xmlChar *fullname;
4258
4259 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4260 if (fullname == NULL) {
4261 xmlVErrMemory(ctxt);
4262 return(0);
4263 }
4264 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4265 attr->name, aprefix);
4266 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4267 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4268 attr->name, aprefix);
4269 if ((fullname != fn) && (fullname != elem->name))
4270 xmlFree(fullname);
4271 }
4272 if (attrDecl == NULL) {
4273 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4274 attr->name, aprefix);
4275 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4276 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4277 attr->name, aprefix);
4278 }
4279
4280
4281 /* Validity Constraint: Attribute Value Type */
4282 if (attrDecl == NULL) {
4283 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4284 "No declaration for attribute %s of element %s\n",
4285 attr->name, elem->name, NULL);
4286 return(0);
4287 }
4288 if (attr->atype == XML_ATTRIBUTE_ID)
4289 xmlRemoveID(doc, attr);
4290 attr->atype = attrDecl->atype;
4291
4292 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4293 if (val == 0) {
4294 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4295 "Syntax of value for attribute %s of %s is not valid\n",
4296 attr->name, elem->name, NULL);
4297 ret = 0;
4298 }
4299
4300 /* Validity constraint: Fixed Attribute Default */
4301 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4302 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4303 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4304 "Value for attribute %s of %s is different from default \"%s\"\n",
4305 attr->name, elem->name, attrDecl->defaultValue);
4306 ret = 0;
4307 }
4308 }
4309
4310 /* Validity Constraint: ID uniqueness */
4311 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4312 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4313 ret = 0;
4314 }
4315
4316 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4317 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4318 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4319 ret = 0;
4320 }
4321
4322 /* Validity Constraint: Notation Attributes */
4323 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4324 xmlEnumerationPtr tree = attrDecl->tree;
4325 xmlNotationPtr nota;
4326
4327 /* First check that the given NOTATION was declared */
4328 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4329 if (nota == NULL)
4330 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4331
4332 if (nota == NULL) {
4333 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4334 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4335 value, attr->name, elem->name);
4336 ret = 0;
4337 }
4338
4339 /* Second, verify that it's among the list */
4340 while (tree != NULL) {
4341 if (xmlStrEqual(tree->name, value)) break;
4342 tree = tree->next;
4343 }
4344 if (tree == NULL) {
4345 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4346"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4347 value, attr->name, elem->name);
4348 ret = 0;
4349 }
4350 }
4351
4352 /* Validity Constraint: Enumeration */
4353 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4354 xmlEnumerationPtr tree = attrDecl->tree;
4355 while (tree != NULL) {
4356 if (xmlStrEqual(tree->name, value)) break;
4357 tree = tree->next;
4358 }
4359 if (tree == NULL) {
4360 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4361 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4362 value, attr->name, elem->name);
4363 ret = 0;
4364 }
4365 }
4366
4367 /* Fixed Attribute Default */
4368 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4369 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4370 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4371 "Value for attribute %s of %s must be \"%s\"\n",
4372 attr->name, elem->name, attrDecl->defaultValue);
4373 ret = 0;
4374 }
4375
4376 /* Extra check for the attribute value */
4377 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4378 attrDecl->atype, value);
4379
4380 return(ret);
4381}
4382
4383/**
4384 * xmlValidateOneNamespace:
4385 * @ctxt: the validation context
4386 * @doc: a document instance
4387 * @elem: an element instance
4388 * @prefix: the namespace prefix
4389 * @ns: an namespace declaration instance
4390 * @value: the attribute value (without entities processing)
4391 *
4392 * DEPRECATED: Internal function, don't use.
4393 *
4394 * Try to validate a single namespace declaration for an element
4395 * basically it does the following checks as described by the
4396 * XML-1.0 recommendation:
4397 * - [ VC: Attribute Value Type ]
4398 * - [ VC: Fixed Attribute Default ]
4399 * - [ VC: Entity Name ]
4400 * - [ VC: Name Token ]
4401 * - [ VC: ID ]
4402 * - [ VC: IDREF ]
4403 * - [ VC: Entity Name ]
4404 * - [ VC: Notation Attributes ]
4405 *
4406 * The ID/IDREF uniqueness and matching are done separately
4407 *
4408 * returns 1 if valid or 0 otherwise
4409 */
4410
4411int
4412xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4413xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4414 /* xmlElementPtr elemDecl; */
4415 xmlAttributePtr attrDecl = NULL;
4416 int val;
4417 int ret = 1;
4418
4419 CHECK_DTD;
4420 if ((elem == NULL) || (elem->name == NULL)) return(0);
4421 if ((ns == NULL) || (ns->href == NULL)) return(0);
4422
4423 if (prefix != NULL) {
4424 xmlChar fn[50];
4425 xmlChar *fullname;
4426
4427 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4428 if (fullname == NULL) {
4429 xmlVErrMemory(ctxt);
4430 return(0);
4431 }
4432 if (ns->prefix != NULL) {
4433 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4434 ns->prefix, BAD_CAST "xmlns");
4435 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4436 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4437 ns->prefix, BAD_CAST "xmlns");
4438 } else {
4439 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4440 BAD_CAST "xmlns", NULL);
4441 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4442 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4443 BAD_CAST "xmlns", NULL);
4444 }
4445 if ((fullname != fn) && (fullname != elem->name))
4446 xmlFree(fullname);
4447 }
4448 if (attrDecl == NULL) {
4449 if (ns->prefix != NULL) {
4450 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4451 ns->prefix, BAD_CAST "xmlns");
4452 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4453 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4454 ns->prefix, BAD_CAST "xmlns");
4455 } else {
4456 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4457 BAD_CAST "xmlns", NULL);
4458 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4459 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4460 BAD_CAST "xmlns", NULL);
4461 }
4462 }
4463
4464
4465 /* Validity Constraint: Attribute Value Type */
4466 if (attrDecl == NULL) {
4467 if (ns->prefix != NULL) {
4468 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4469 "No declaration for attribute xmlns:%s of element %s\n",
4470 ns->prefix, elem->name, NULL);
4471 } else {
4472 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4473 "No declaration for attribute xmlns of element %s\n",
4474 elem->name, NULL, NULL);
4475 }
4476 return(0);
4477 }
4478
4479 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4480 if (val == 0) {
4481 if (ns->prefix != NULL) {
4482 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4483 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4484 ns->prefix, elem->name, NULL);
4485 } else {
4486 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4487 "Syntax of value for attribute xmlns of %s is not valid\n",
4488 elem->name, NULL, NULL);
4489 }
4490 ret = 0;
4491 }
4492
4493 /* Validity constraint: Fixed Attribute Default */
4494 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4495 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4496 if (ns->prefix != NULL) {
4497 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4498 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4499 ns->prefix, elem->name, attrDecl->defaultValue);
4500 } else {
4501 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4502 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4503 elem->name, attrDecl->defaultValue, NULL);
4504 }
4505 ret = 0;
4506 }
4507 }
4508
4509 /*
4510 * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4511 * xmlAddID and xmlAddRef for namespace declarations, but it makes
4512 * no practical sense to use ID types anyway.
4513 */
4514#if 0
4515 /* Validity Constraint: ID uniqueness */
4516 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4517 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4518 ret = 0;
4519 }
4520
4521 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4522 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4523 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4524 ret = 0;
4525 }
4526#endif
4527
4528 /* Validity Constraint: Notation Attributes */
4529 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4530 xmlEnumerationPtr tree = attrDecl->tree;
4531 xmlNotationPtr nota;
4532
4533 /* First check that the given NOTATION was declared */
4534 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4535 if (nota == NULL)
4536 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4537
4538 if (nota == NULL) {
4539 if (ns->prefix != NULL) {
4540 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4541 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4542 value, ns->prefix, elem->name);
4543 } else {
4544 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4545 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4546 value, elem->name, NULL);
4547 }
4548 ret = 0;
4549 }
4550
4551 /* Second, verify that it's among the list */
4552 while (tree != NULL) {
4553 if (xmlStrEqual(tree->name, value)) break;
4554 tree = tree->next;
4555 }
4556 if (tree == NULL) {
4557 if (ns->prefix != NULL) {
4558 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4559"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4560 value, ns->prefix, elem->name);
4561 } else {
4562 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4563"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4564 value, elem->name, NULL);
4565 }
4566 ret = 0;
4567 }
4568 }
4569
4570 /* Validity Constraint: Enumeration */
4571 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4572 xmlEnumerationPtr tree = attrDecl->tree;
4573 while (tree != NULL) {
4574 if (xmlStrEqual(tree->name, value)) break;
4575 tree = tree->next;
4576 }
4577 if (tree == NULL) {
4578 if (ns->prefix != NULL) {
4579 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4580"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4581 value, ns->prefix, elem->name);
4582 } else {
4583 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4584"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4585 value, elem->name, NULL);
4586 }
4587 ret = 0;
4588 }
4589 }
4590
4591 /* Fixed Attribute Default */
4592 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4593 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4594 if (ns->prefix != NULL) {
4595 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4596 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4597 ns->prefix, elem->name, attrDecl->defaultValue);
4598 } else {
4599 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4600 "Value for attribute xmlns of %s must be \"%s\"\n",
4601 elem->name, attrDecl->defaultValue, NULL);
4602 }
4603 ret = 0;
4604 }
4605
4606 /* Extra check for the attribute value */
4607 if (ns->prefix != NULL) {
4608 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4609 attrDecl->atype, value);
4610 } else {
4611 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4612 attrDecl->atype, value);
4613 }
4614
4615 return(ret);
4616}
4617
4618#ifndef LIBXML_REGEXP_ENABLED
4619/**
4620 * xmlValidateSkipIgnorable:
4621 * @ctxt: the validation context
4622 * @child: the child list
4623 *
4624 * Skip ignorable elements w.r.t. the validation process
4625 *
4626 * returns the first element to consider for validation of the content model
4627 */
4628
4629static xmlNodePtr
4630xmlValidateSkipIgnorable(xmlNodePtr child) {
4631 while (child != NULL) {
4632 switch (child->type) {
4633 /* These things are ignored (skipped) during validation. */
4634 case XML_PI_NODE:
4635 case XML_COMMENT_NODE:
4636 case XML_XINCLUDE_START:
4637 case XML_XINCLUDE_END:
4638 child = child->next;
4639 break;
4640 case XML_TEXT_NODE:
4641 if (xmlIsBlankNode(child))
4642 child = child->next;
4643 else
4644 return(child);
4645 break;
4646 /* keep current node */
4647 default:
4648 return(child);
4649 }
4650 }
4651 return(child);
4652}
4653
4654/**
4655 * xmlValidateElementType:
4656 * @ctxt: the validation context
4657 *
4658 * Try to validate the content model of an element internal function
4659 *
4660 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4661 * reference is found and -3 if the validation succeeded but
4662 * the content model is not determinist.
4663 */
4664
4665static int
4666xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4667 int ret = -1;
4668 int determinist = 1;
4669
4670 NODE = xmlValidateSkipIgnorable(NODE);
4671 if ((NODE == NULL) && (CONT == NULL))
4672 return(1);
4673 if ((NODE == NULL) &&
4674 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4675 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4676 return(1);
4677 }
4678 if (CONT == NULL) return(-1);
4679 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4680 return(-2);
4681
4682 /*
4683 * We arrive here when more states need to be examined
4684 */
4685cont:
4686
4687 /*
4688 * We just recovered from a rollback generated by a possible
4689 * epsilon transition, go directly to the analysis phase
4690 */
4691 if (STATE == ROLLBACK_PARENT) {
4692 ret = 1;
4693 goto analyze;
4694 }
4695
4696 /*
4697 * we may have to save a backup state here. This is the equivalent
4698 * of handling epsilon transition in NFAs.
4699 */
4700 if ((CONT != NULL) &&
4701 ((CONT->parent == NULL) ||
4702 (CONT->parent == (xmlElementContentPtr) 1) ||
4703 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4704 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4705 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4706 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4707 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4708 return(0);
4709 }
4710
4711
4712 /*
4713 * Check first if the content matches
4714 */
4715 switch (CONT->type) {
4716 case XML_ELEMENT_CONTENT_PCDATA:
4717 if (NODE == NULL) {
4718 ret = 0;
4719 break;
4720 }
4721 if (NODE->type == XML_TEXT_NODE) {
4722 /*
4723 * go to next element in the content model
4724 * skipping ignorable elems
4725 */
4726 do {
4727 NODE = NODE->next;
4728 NODE = xmlValidateSkipIgnorable(NODE);
4729 if ((NODE != NULL) &&
4730 (NODE->type == XML_ENTITY_REF_NODE))
4731 return(-2);
4732 } while ((NODE != NULL) &&
4733 ((NODE->type != XML_ELEMENT_NODE) &&
4734 (NODE->type != XML_TEXT_NODE) &&
4735 (NODE->type != XML_CDATA_SECTION_NODE)));
4736 ret = 1;
4737 break;
4738 } else {
4739 ret = 0;
4740 break;
4741 }
4742 break;
4743 case XML_ELEMENT_CONTENT_ELEMENT:
4744 if (NODE == NULL) {
4745 ret = 0;
4746 break;
4747 }
4748 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4749 (xmlStrEqual(NODE->name, CONT->name)));
4750 if (ret == 1) {
4751 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4752 ret = (CONT->prefix == NULL);
4753 } else if (CONT->prefix == NULL) {
4754 ret = 0;
4755 } else {
4756 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4757 }
4758 }
4759 if (ret == 1) {
4760 /*
4761 * go to next element in the content model
4762 * skipping ignorable elems
4763 */
4764 do {
4765 NODE = NODE->next;
4766 NODE = xmlValidateSkipIgnorable(NODE);
4767 if ((NODE != NULL) &&
4768 (NODE->type == XML_ENTITY_REF_NODE))
4769 return(-2);
4770 } while ((NODE != NULL) &&
4771 ((NODE->type != XML_ELEMENT_NODE) &&
4772 (NODE->type != XML_TEXT_NODE) &&
4773 (NODE->type != XML_CDATA_SECTION_NODE)));
4774 } else {
4775 ret = 0;
4776 break;
4777 }
4778 break;
4779 case XML_ELEMENT_CONTENT_OR:
4780 /*
4781 * Small optimization.
4782 */
4783 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4784 if ((NODE == NULL) ||
4785 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4786 DEPTH++;
4787 CONT = CONT->c2;
4788 goto cont;
4789 }
4790 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4791 ret = (CONT->c1->prefix == NULL);
4792 } else if (CONT->c1->prefix == NULL) {
4793 ret = 0;
4794 } else {
4795 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4796 }
4797 if (ret == 0) {
4798 DEPTH++;
4799 CONT = CONT->c2;
4800 goto cont;
4801 }
4802 }
4803
4804 /*
4805 * save the second branch 'or' branch
4806 */
4807 if (vstateVPush(ctxt, CONT->c2, NODE, DEPTH + 1,
4808 OCCURS, ROLLBACK_OR) < 0)
4809 return(-1);
4810 DEPTH++;
4811 CONT = CONT->c1;
4812 goto cont;
4813 case XML_ELEMENT_CONTENT_SEQ:
4814 /*
4815 * Small optimization.
4816 */
4817 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4818 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4819 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4820 if ((NODE == NULL) ||
4821 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4822 DEPTH++;
4823 CONT = CONT->c2;
4824 goto cont;
4825 }
4826 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4827 ret = (CONT->c1->prefix == NULL);
4828 } else if (CONT->c1->prefix == NULL) {
4829 ret = 0;
4830 } else {
4831 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4832 }
4833 if (ret == 0) {
4834 DEPTH++;
4835 CONT = CONT->c2;
4836 goto cont;
4837 }
4838 }
4839 DEPTH++;
4840 CONT = CONT->c1;
4841 goto cont;
4842 }
4843
4844 /*
4845 * At this point handle going up in the tree
4846 */
4847 if (ret == -1) {
4848 return(ret);
4849 }
4850analyze:
4851 while (CONT != NULL) {
4852 /*
4853 * First do the analysis depending on the occurrence model at
4854 * this level.
4855 */
4856 if (ret == 0) {
4857 switch (CONT->ocur) {
4858 xmlNodePtr cur;
4859
4860 case XML_ELEMENT_CONTENT_ONCE:
4861 cur = ctxt->vstate->node;
4862 if (vstateVPop(ctxt) < 0 ) {
4863 return(0);
4864 }
4865 if (cur != ctxt->vstate->node)
4866 determinist = -3;
4867 goto cont;
4868 case XML_ELEMENT_CONTENT_PLUS:
4869 if (OCCURRENCE == 0) {
4870 cur = ctxt->vstate->node;
4871 if (vstateVPop(ctxt) < 0 ) {
4872 return(0);
4873 }
4874 if (cur != ctxt->vstate->node)
4875 determinist = -3;
4876 goto cont;
4877 }
4878 ret = 1;
4879 break;
4880 case XML_ELEMENT_CONTENT_MULT:
4881 ret = 1;
4882 break;
4883 case XML_ELEMENT_CONTENT_OPT:
4884 ret = 1;
4885 break;
4886 }
4887 } else {
4888 switch (CONT->ocur) {
4889 case XML_ELEMENT_CONTENT_OPT:
4890 ret = 1;
4891 break;
4892 case XML_ELEMENT_CONTENT_ONCE:
4893 ret = 1;
4894 break;
4895 case XML_ELEMENT_CONTENT_PLUS:
4896 if (STATE == ROLLBACK_PARENT) {
4897 ret = 1;
4898 break;
4899 }
4900 if (NODE == NULL) {
4901 ret = 1;
4902 break;
4903 }
4904 SET_OCCURRENCE;
4905 goto cont;
4906 case XML_ELEMENT_CONTENT_MULT:
4907 if (STATE == ROLLBACK_PARENT) {
4908 ret = 1;
4909 break;
4910 }
4911 if (NODE == NULL) {
4912 ret = 1;
4913 break;
4914 }
4915 /* SET_OCCURRENCE; */
4916 goto cont;
4917 }
4918 }
4919 STATE = 0;
4920
4921 /*
4922 * Then act accordingly at the parent level
4923 */
4924 RESET_OCCURRENCE;
4925 if ((CONT->parent == NULL) ||
4926 (CONT->parent == (xmlElementContentPtr) 1))
4927 break;
4928
4929 switch (CONT->parent->type) {
4930 case XML_ELEMENT_CONTENT_PCDATA:
4931 return(-1);
4932 case XML_ELEMENT_CONTENT_ELEMENT:
4933 return(-1);
4934 case XML_ELEMENT_CONTENT_OR:
4935 if (ret == 1) {
4936 CONT = CONT->parent;
4937 DEPTH--;
4938 } else {
4939 CONT = CONT->parent;
4940 DEPTH--;
4941 }
4942 break;
4943 case XML_ELEMENT_CONTENT_SEQ:
4944 if (ret == 0) {
4945 CONT = CONT->parent;
4946 DEPTH--;
4947 } else if (CONT == CONT->parent->c1) {
4948 CONT = CONT->parent->c2;
4949 goto cont;
4950 } else {
4951 CONT = CONT->parent;
4952 DEPTH--;
4953 }
4954 }
4955 }
4956 if (NODE != NULL) {
4957 xmlNodePtr cur;
4958
4959 cur = ctxt->vstate->node;
4960 if (vstateVPop(ctxt) < 0 ) {
4961 return(0);
4962 }
4963 if (cur != ctxt->vstate->node)
4964 determinist = -3;
4965 goto cont;
4966 }
4967 if (ret == 0) {
4968 xmlNodePtr cur;
4969
4970 cur = ctxt->vstate->node;
4971 if (vstateVPop(ctxt) < 0 ) {
4972 return(0);
4973 }
4974 if (cur != ctxt->vstate->node)
4975 determinist = -3;
4976 goto cont;
4977 }
4978 return(determinist);
4979}
4980#endif
4981
4982/**
4983 * xmlSnprintfElements:
4984 * @buf: an output buffer
4985 * @size: the size of the buffer
4986 * @content: An element
4987 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4988 *
4989 * This will dump the list of elements to the buffer
4990 * Intended just for the debug routine
4991 */
4992static void
4993xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
4994 xmlNodePtr cur;
4995 int len;
4996
4997 if (node == NULL) return;
4998 if (glob) strcat(buf, "(");
4999 cur = node;
5000 while (cur != NULL) {
5001 len = strlen(buf);
5002 if (size - len < 50) {
5003 if ((size - len > 4) && (buf[len - 1] != '.'))
5004 strcat(buf, " ...");
5005 return;
5006 }
5007 switch (cur->type) {
5008 case XML_ELEMENT_NODE:
5009 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5010 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5011 if ((size - len > 4) && (buf[len - 1] != '.'))
5012 strcat(buf, " ...");
5013 return;
5014 }
5015 strcat(buf, (char *) cur->ns->prefix);
5016 strcat(buf, ":");
5017 }
5018 if (size - len < xmlStrlen(cur->name) + 10) {
5019 if ((size - len > 4) && (buf[len - 1] != '.'))
5020 strcat(buf, " ...");
5021 return;
5022 }
5023 if (cur->name != NULL)
5024 strcat(buf, (char *) cur->name);
5025 if (cur->next != NULL)
5026 strcat(buf, " ");
5027 break;
5028 case XML_TEXT_NODE:
5029 if (xmlIsBlankNode(cur))
5030 break;
5031 /* Falls through. */
5032 case XML_CDATA_SECTION_NODE:
5033 case XML_ENTITY_REF_NODE:
5034 strcat(buf, "CDATA");
5035 if (cur->next != NULL)
5036 strcat(buf, " ");
5037 break;
5038 case XML_ATTRIBUTE_NODE:
5039 case XML_DOCUMENT_NODE:
5040 case XML_HTML_DOCUMENT_NODE:
5041 case XML_DOCUMENT_TYPE_NODE:
5042 case XML_DOCUMENT_FRAG_NODE:
5043 case XML_NOTATION_NODE:
5044 case XML_NAMESPACE_DECL:
5045 strcat(buf, "???");
5046 if (cur->next != NULL)
5047 strcat(buf, " ");
5048 break;
5049 case XML_ENTITY_NODE:
5050 case XML_PI_NODE:
5051 case XML_DTD_NODE:
5052 case XML_COMMENT_NODE:
5053 case XML_ELEMENT_DECL:
5054 case XML_ATTRIBUTE_DECL:
5055 case XML_ENTITY_DECL:
5056 case XML_XINCLUDE_START:
5057 case XML_XINCLUDE_END:
5058 break;
5059 }
5060 cur = cur->next;
5061 }
5062 if (glob) strcat(buf, ")");
5063}
5064
5065/**
5066 * xmlValidateElementContent:
5067 * @ctxt: the validation context
5068 * @child: the child list
5069 * @elemDecl: pointer to the element declaration
5070 * @warn: emit the error message
5071 * @parent: the parent element (for error reporting)
5072 *
5073 * Try to validate the content model of an element
5074 *
5075 * returns 1 if valid or 0 if not and -1 in case of error
5076 */
5077
5078static int
5079xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
5080 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5081 int ret = 1;
5082#ifndef LIBXML_REGEXP_ENABLED
5083 xmlNodePtr repl = NULL, last = NULL, tmp;
5084#endif
5085 xmlNodePtr cur;
5086 xmlElementContentPtr cont;
5087 const xmlChar *name;
5088
5089 if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
5090 return(-1);
5091 cont = elemDecl->content;
5092 name = elemDecl->name;
5093
5094#ifdef LIBXML_REGEXP_ENABLED
5095 /* Build the regexp associated to the content model */
5096 if (elemDecl->contModel == NULL)
5097 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5098 if (elemDecl->contModel == NULL) {
5099 return(-1);
5100 } else {
5101 xmlRegExecCtxtPtr exec;
5102
5103 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5104 return(-1);
5105 }
5106 ctxt->nodeMax = 0;
5107 ctxt->nodeNr = 0;
5108 ctxt->nodeTab = NULL;
5109 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5110 if (exec == NULL) {
5111 xmlVErrMemory(ctxt);
5112 return(-1);
5113 }
5114 cur = child;
5115 while (cur != NULL) {
5116 switch (cur->type) {
5117 case XML_ENTITY_REF_NODE:
5118 /*
5119 * Push the current node to be able to roll back
5120 * and process within the entity
5121 */
5122 if ((cur->children != NULL) &&
5123 (cur->children->children != NULL)) {
5124 nodeVPush(ctxt, cur);
5125 cur = cur->children->children;
5126 continue;
5127 }
5128 break;
5129 case XML_TEXT_NODE:
5130 if (xmlIsBlankNode(cur))
5131 break;
5132 ret = 0;
5133 goto fail;
5134 case XML_CDATA_SECTION_NODE:
5135 /* TODO */
5136 ret = 0;
5137 goto fail;
5138 case XML_ELEMENT_NODE:
5139 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5140 xmlChar fn[50];
5141 xmlChar *fullname;
5142
5143 fullname = xmlBuildQName(cur->name,
5144 cur->ns->prefix, fn, 50);
5145 if (fullname == NULL) {
5146 xmlVErrMemory(ctxt);
5147 ret = -1;
5148 goto fail;
5149 }
5150 ret = xmlRegExecPushString(exec, fullname, NULL);
5151 if ((fullname != fn) && (fullname != cur->name))
5152 xmlFree(fullname);
5153 } else {
5154 ret = xmlRegExecPushString(exec, cur->name, NULL);
5155 }
5156 break;
5157 default:
5158 break;
5159 }
5160 if (ret == XML_REGEXP_OUT_OF_MEMORY)
5161 xmlVErrMemory(ctxt);
5162 /*
5163 * Switch to next element
5164 */
5165 cur = cur->next;
5166 while (cur == NULL) {
5167 cur = nodeVPop(ctxt);
5168 if (cur == NULL)
5169 break;
5170 cur = cur->next;
5171 }
5172 }
5173 ret = xmlRegExecPushString(exec, NULL, NULL);
5174 if (ret == XML_REGEXP_OUT_OF_MEMORY)
5175 xmlVErrMemory(ctxt);
5176fail:
5177 xmlRegFreeExecCtxt(exec);
5178 }
5179#else /* LIBXML_REGEXP_ENABLED */
5180 /*
5181 * Allocate the stack
5182 */
5183 ctxt->vstateMax = 8;
5184 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5185 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5186 if (ctxt->vstateTab == NULL) {
5187 xmlVErrMemory(ctxt);
5188 return(-1);
5189 }
5190 /*
5191 * The first entry in the stack is reserved to the current state
5192 */
5193 ctxt->nodeMax = 0;
5194 ctxt->nodeNr = 0;
5195 ctxt->nodeTab = NULL;
5196 ctxt->vstate = &ctxt->vstateTab[0];
5197 ctxt->vstateNr = 1;
5198 CONT = cont;
5199 NODE = child;
5200 DEPTH = 0;
5201 OCCURS = 0;
5202 STATE = 0;
5203 ret = xmlValidateElementType(ctxt);
5204 if ((ret == -3) && (warn)) {
5205 char expr[5000];
5206 expr[0] = 0;
5207 xmlSnprintfElementContent(expr, 5000, elemDecl->content, 1);
5208 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
5209 XML_DTD_CONTENT_NOT_DETERMINIST,
5210 "Content model of %s is not deterministic: %s\n",
5211 name, BAD_CAST expr, NULL);
5212 } else if (ret == -2) {
5213 /*
5214 * An entities reference appeared at this level.
5215 * Build a minimal representation of this node content
5216 * sufficient to run the validation process on it
5217 */
5218 cur = child;
5219 while (cur != NULL) {
5220 switch (cur->type) {
5221 case XML_ENTITY_REF_NODE:
5222 /*
5223 * Push the current node to be able to roll back
5224 * and process within the entity
5225 */
5226 if ((cur->children != NULL) &&
5227 (cur->children->children != NULL)) {
5228 nodeVPush(ctxt, cur);
5229 cur = cur->children->children;
5230 continue;
5231 }
5232 break;
5233 case XML_TEXT_NODE:
5234 if (xmlIsBlankNode(cur))
5235 break;
5236 /* no break on purpose */
5237 case XML_CDATA_SECTION_NODE:
5238 /* no break on purpose */
5239 case XML_ELEMENT_NODE:
5240 /*
5241 * Allocate a new node and minimally fills in
5242 * what's required
5243 */
5244 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5245 if (tmp == NULL) {
5246 xmlVErrMemory(ctxt);
5247 xmlFreeNodeList(repl);
5248 ret = -1;
5249 goto done;
5250 }
5251 tmp->type = cur->type;
5252 tmp->name = cur->name;
5253 tmp->ns = cur->ns;
5254 tmp->next = NULL;
5255 tmp->content = NULL;
5256 if (repl == NULL)
5257 repl = last = tmp;
5258 else {
5259 last->next = tmp;
5260 last = tmp;
5261 }
5262 if (cur->type == XML_CDATA_SECTION_NODE) {
5263 /*
5264 * E59 spaces in CDATA does not match the
5265 * nonterminal S
5266 */
5267 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5268 }
5269 break;
5270 default:
5271 break;
5272 }
5273 /*
5274 * Switch to next element
5275 */
5276 cur = cur->next;
5277 while (cur == NULL) {
5278 cur = nodeVPop(ctxt);
5279 if (cur == NULL)
5280 break;
5281 cur = cur->next;
5282 }
5283 }
5284
5285 /*
5286 * Relaunch the validation
5287 */
5288 ctxt->vstate = &ctxt->vstateTab[0];
5289 ctxt->vstateNr = 1;
5290 CONT = cont;
5291 NODE = repl;
5292 DEPTH = 0;
5293 OCCURS = 0;
5294 STATE = 0;
5295 ret = xmlValidateElementType(ctxt);
5296 }
5297#endif /* LIBXML_REGEXP_ENABLED */
5298 if ((warn) && ((ret != 1) && (ret != -3))) {
5299 if (ctxt != NULL) {
5300 char expr[5000];
5301 char list[5000];
5302
5303 expr[0] = 0;
5304 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5305 list[0] = 0;
5306#ifndef LIBXML_REGEXP_ENABLED
5307 if (repl != NULL)
5308 xmlSnprintfElements(&list[0], 5000, repl, 1);
5309 else
5310#endif /* LIBXML_REGEXP_ENABLED */
5311 xmlSnprintfElements(&list[0], 5000, child, 1);
5312
5313 if (name != NULL) {
5314 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5315 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5316 name, BAD_CAST expr, BAD_CAST list);
5317 } else {
5318 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5319 "Element content does not follow the DTD, expecting %s, got %s\n",
5320 BAD_CAST expr, BAD_CAST list, NULL);
5321 }
5322 } else {
5323 if (name != NULL) {
5324 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5325 "Element %s content does not follow the DTD\n",
5326 name, NULL, NULL);
5327 } else {
5328 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5329 "Element content does not follow the DTD\n",
5330 NULL, NULL, NULL);
5331 }
5332 }
5333 ret = 0;
5334 }
5335 if (ret == -3)
5336 ret = 1;
5337
5338#ifndef LIBXML_REGEXP_ENABLED
5339done:
5340 /*
5341 * Deallocate the copy if done, and free up the validation stack
5342 */
5343 while (repl != NULL) {
5344 tmp = repl->next;
5345 xmlFree(repl);
5346 repl = tmp;
5347 }
5348 ctxt->vstateMax = 0;
5349 if (ctxt->vstateTab != NULL) {
5350 xmlFree(ctxt->vstateTab);
5351 ctxt->vstateTab = NULL;
5352 }
5353#endif
5354 ctxt->nodeMax = 0;
5355 ctxt->nodeNr = 0;
5356 if (ctxt->nodeTab != NULL) {
5357 xmlFree(ctxt->nodeTab);
5358 ctxt->nodeTab = NULL;
5359 }
5360 return(ret);
5361
5362}
5363
5364/**
5365 * xmlValidateCdataElement:
5366 * @ctxt: the validation context
5367 * @doc: a document instance
5368 * @elem: an element instance
5369 *
5370 * Check that an element follows #CDATA
5371 *
5372 * returns 1 if valid or 0 otherwise
5373 */
5374static int
5375xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5376 xmlNodePtr elem) {
5377 int ret = 1;
5378 xmlNodePtr cur, child;
5379
5380 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5381 (elem->type != XML_ELEMENT_NODE))
5382 return(0);
5383
5384 child = elem->children;
5385
5386 cur = child;
5387 while (cur != NULL) {
5388 switch (cur->type) {
5389 case XML_ENTITY_REF_NODE:
5390 /*
5391 * Push the current node to be able to roll back
5392 * and process within the entity
5393 */
5394 if ((cur->children != NULL) &&
5395 (cur->children->children != NULL)) {
5396 nodeVPush(ctxt, cur);
5397 cur = cur->children->children;
5398 continue;
5399 }
5400 break;
5401 case XML_COMMENT_NODE:
5402 case XML_PI_NODE:
5403 case XML_TEXT_NODE:
5404 case XML_CDATA_SECTION_NODE:
5405 break;
5406 default:
5407 ret = 0;
5408 goto done;
5409 }
5410 /*
5411 * Switch to next element
5412 */
5413 cur = cur->next;
5414 while (cur == NULL) {
5415 cur = nodeVPop(ctxt);
5416 if (cur == NULL)
5417 break;
5418 cur = cur->next;
5419 }
5420 }
5421done:
5422 ctxt->nodeMax = 0;
5423 ctxt->nodeNr = 0;
5424 if (ctxt->nodeTab != NULL) {
5425 xmlFree(ctxt->nodeTab);
5426 ctxt->nodeTab = NULL;
5427 }
5428 return(ret);
5429}
5430
5431#ifdef LIBXML_REGEXP_ENABLED
5432/**
5433 * xmlValidateCheckMixed:
5434 * @ctxt: the validation context
5435 * @cont: the mixed content model
5436 * @qname: the qualified name as appearing in the serialization
5437 *
5438 * Check if the given node is part of the content model.
5439 *
5440 * Returns 1 if yes, 0 if no, -1 in case of error
5441 */
5442static int
5443xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
5444 xmlElementContentPtr cont, const xmlChar *qname) {
5445 const xmlChar *name;
5446 int plen;
5447 name = xmlSplitQName3(qname, &plen);
5448
5449 if (name == NULL) {
5450 while (cont != NULL) {
5451 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5452 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5453 return(1);
5454 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5455 (cont->c1 != NULL) &&
5456 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5457 if ((cont->c1->prefix == NULL) &&
5458 (xmlStrEqual(cont->c1->name, qname)))
5459 return(1);
5460 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5461 (cont->c1 == NULL) ||
5462 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5463 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5464 "Internal: MIXED struct corrupted\n",
5465 NULL);
5466 break;
5467 }
5468 cont = cont->c2;
5469 }
5470 } else {
5471 while (cont != NULL) {
5472 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5473 if ((cont->prefix != NULL) &&
5474 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5475 (xmlStrEqual(cont->name, name)))
5476 return(1);
5477 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5478 (cont->c1 != NULL) &&
5479 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5480 if ((cont->c1->prefix != NULL) &&
5481 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5482 (xmlStrEqual(cont->c1->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_PCDATA)){
5487 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5488 "Internal: MIXED struct corrupted\n",
5489 NULL);
5490 break;
5491 }
5492 cont = cont->c2;
5493 }
5494 }
5495 return(0);
5496}
5497#endif /* LIBXML_REGEXP_ENABLED */
5498
5499/**
5500 * xmlValidGetElemDecl:
5501 * @ctxt: the validation context
5502 * @doc: a document instance
5503 * @elem: an element instance
5504 * @extsubset: pointer, (out) indicate if the declaration was found
5505 * in the external subset.
5506 *
5507 * Finds a declaration associated to an element in the document.
5508 *
5509 * returns the pointer to the declaration or NULL if not found.
5510 */
5511static xmlElementPtr
5512xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5513 xmlNodePtr elem, int *extsubset) {
5514 xmlElementPtr elemDecl = NULL;
5515 const xmlChar *prefix = NULL;
5516
5517 if ((ctxt == NULL) || (doc == NULL) ||
5518 (elem == NULL) || (elem->name == NULL))
5519 return(NULL);
5520 if (extsubset != NULL)
5521 *extsubset = 0;
5522
5523 /*
5524 * Fetch the declaration for the qualified name
5525 */
5526 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5527 prefix = elem->ns->prefix;
5528
5529 if (prefix != NULL) {
5530 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5531 elem->name, prefix);
5532 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5533 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5534 elem->name, prefix);
5535 if ((elemDecl != NULL) && (extsubset != NULL))
5536 *extsubset = 1;
5537 }
5538 }
5539
5540 /*
5541 * Fetch the declaration for the non qualified name
5542 * This is "non-strict" validation should be done on the
5543 * full QName but in that case being flexible makes sense.
5544 */
5545 if (elemDecl == NULL) {
5546 elemDecl = xmlGetDtdQElementDesc(doc->intSubset, elem->name, NULL);
5547 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5548 elemDecl = xmlGetDtdQElementDesc(doc->extSubset, elem->name, NULL);
5549 if ((elemDecl != NULL) && (extsubset != NULL))
5550 *extsubset = 1;
5551 }
5552 }
5553 if (elemDecl == NULL) {
5554 xmlErrValidNode(ctxt, elem,
5555 XML_DTD_UNKNOWN_ELEM,
5556 "No declaration for element %s\n",
5557 elem->name, NULL, NULL);
5558 }
5559 return(elemDecl);
5560}
5561
5562#ifdef LIBXML_REGEXP_ENABLED
5563/**
5564 * xmlValidatePushElement:
5565 * @ctxt: the validation context
5566 * @doc: a document instance
5567 * @elem: an element instance
5568 * @qname: the qualified name as appearing in the serialization
5569 *
5570 * DEPRECATED: Internal function, don't use.
5571 *
5572 * Push a new element start on the validation stack.
5573 *
5574 * returns 1 if no validation problem was found or 0 otherwise
5575 */
5576int
5577xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5578 xmlNodePtr elem, const xmlChar *qname) {
5579 int ret = 1;
5580 xmlElementPtr eDecl;
5581 int extsubset = 0;
5582
5583 if (ctxt == NULL)
5584 return(0);
5585/* printf("PushElem %s\n", qname); */
5586 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5587 xmlValidStatePtr state = ctxt->vstate;
5588 xmlElementPtr elemDecl;
5589
5590 /*
5591 * Check the new element against the content model of the new elem.
5592 */
5593 if (state->elemDecl != NULL) {
5594 elemDecl = state->elemDecl;
5595
5596 switch(elemDecl->etype) {
5597 case XML_ELEMENT_TYPE_UNDEFINED:
5598 ret = 0;
5599 break;
5600 case XML_ELEMENT_TYPE_EMPTY:
5601 xmlErrValidNode(ctxt, state->node,
5602 XML_DTD_NOT_EMPTY,
5603 "Element %s was declared EMPTY this one has content\n",
5604 state->node->name, NULL, NULL);
5605 ret = 0;
5606 break;
5607 case XML_ELEMENT_TYPE_ANY:
5608 /* I don't think anything is required then */
5609 break;
5610 case XML_ELEMENT_TYPE_MIXED:
5611 /* simple case of declared as #PCDATA */
5612 if ((elemDecl->content != NULL) &&
5613 (elemDecl->content->type ==
5614 XML_ELEMENT_CONTENT_PCDATA)) {
5615 xmlErrValidNode(ctxt, state->node,
5616 XML_DTD_NOT_PCDATA,
5617 "Element %s was declared #PCDATA but contains non text nodes\n",
5618 state->node->name, NULL, NULL);
5619 ret = 0;
5620 } else {
5621 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5622 qname);
5623 if (ret != 1) {
5624 xmlErrValidNode(ctxt, state->node,
5625 XML_DTD_INVALID_CHILD,
5626 "Element %s is not declared in %s list of possible children\n",
5627 qname, state->node->name, NULL);
5628 }
5629 }
5630 break;
5631 case XML_ELEMENT_TYPE_ELEMENT:
5632 /*
5633 * TODO:
5634 * VC: Standalone Document Declaration
5635 * - element types with element content, if white space
5636 * occurs directly within any instance of those types.
5637 */
5638 if (state->exec != NULL) {
5639 ret = xmlRegExecPushString(state->exec, qname, NULL);
5640 if (ret == XML_REGEXP_OUT_OF_MEMORY) {
5641 xmlVErrMemory(ctxt);
5642 return(0);
5643 }
5644 if (ret < 0) {
5645 xmlErrValidNode(ctxt, state->node,
5646 XML_DTD_CONTENT_MODEL,
5647 "Element %s content does not follow the DTD, Misplaced %s\n",
5648 state->node->name, qname, NULL);
5649 ret = 0;
5650 } else {
5651 ret = 1;
5652 }
5653 }
5654 break;
5655 }
5656 }
5657 }
5658 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5659 vstateVPush(ctxt, eDecl, elem);
5660 return(ret);
5661}
5662
5663/**
5664 * xmlValidatePushCData:
5665 * @ctxt: the validation context
5666 * @data: some character data read
5667 * @len: the length of the data
5668 *
5669 * DEPRECATED: Internal function, don't use.
5670 *
5671 * check the CData parsed for validation in the current stack
5672 *
5673 * returns 1 if no validation problem was found or 0 otherwise
5674 */
5675int
5676xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5677 int ret = 1;
5678
5679/* printf("CDATA %s %d\n", data, len); */
5680 if (ctxt == NULL)
5681 return(0);
5682 if (len <= 0)
5683 return(ret);
5684 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5685 xmlValidStatePtr state = ctxt->vstate;
5686 xmlElementPtr elemDecl;
5687
5688 /*
5689 * Check the new element against the content model of the new elem.
5690 */
5691 if (state->elemDecl != NULL) {
5692 elemDecl = state->elemDecl;
5693
5694 switch(elemDecl->etype) {
5695 case XML_ELEMENT_TYPE_UNDEFINED:
5696 ret = 0;
5697 break;
5698 case XML_ELEMENT_TYPE_EMPTY:
5699 xmlErrValidNode(ctxt, state->node,
5700 XML_DTD_NOT_EMPTY,
5701 "Element %s was declared EMPTY this one has content\n",
5702 state->node->name, NULL, NULL);
5703 ret = 0;
5704 break;
5705 case XML_ELEMENT_TYPE_ANY:
5706 break;
5707 case XML_ELEMENT_TYPE_MIXED:
5708 break;
5709 case XML_ELEMENT_TYPE_ELEMENT: {
5710 int i;
5711
5712 for (i = 0;i < len;i++) {
5713 if (!IS_BLANK_CH(data[i])) {
5714 xmlErrValidNode(ctxt, state->node,
5715 XML_DTD_CONTENT_MODEL,
5716 "Element %s content does not follow the DTD, Text not allowed\n",
5717 state->node->name, NULL, NULL);
5718 ret = 0;
5719 goto done;
5720 }
5721 }
5722 /*
5723 * TODO:
5724 * VC: Standalone Document Declaration
5725 * element types with element content, if white space
5726 * occurs directly within any instance of those types.
5727 */
5728 break;
5729 }
5730 }
5731 }
5732 }
5733done:
5734 return(ret);
5735}
5736
5737/**
5738 * xmlValidatePopElement:
5739 * @ctxt: the validation context
5740 * @doc: a document instance
5741 * @elem: an element instance
5742 * @qname: the qualified name as appearing in the serialization
5743 *
5744 * DEPRECATED: Internal function, don't use.
5745 *
5746 * Pop the element end from the validation stack.
5747 *
5748 * returns 1 if no validation problem was found or 0 otherwise
5749 */
5750int
5751xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
5752 xmlNodePtr elem ATTRIBUTE_UNUSED,
5753 const xmlChar *qname ATTRIBUTE_UNUSED) {
5754 int ret = 1;
5755
5756 if (ctxt == NULL)
5757 return(0);
5758/* printf("PopElem %s\n", qname); */
5759 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5760 xmlValidStatePtr state = ctxt->vstate;
5761 xmlElementPtr elemDecl;
5762
5763 /*
5764 * Check the new element against the content model of the new elem.
5765 */
5766 if (state->elemDecl != NULL) {
5767 elemDecl = state->elemDecl;
5768
5769 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5770 if (state->exec != NULL) {
5771 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5772 if (ret <= 0) {
5773 if (ret == XML_REGEXP_OUT_OF_MEMORY)
5774 xmlVErrMemory(ctxt);
5775 else
5776 xmlErrValidNode(ctxt, state->node,
5777 XML_DTD_CONTENT_MODEL,
5778 "Element %s content does not follow the DTD, Expecting more children\n",
5779 state->node->name, NULL,NULL);
5780 ret = 0;
5781 } else {
5782 /*
5783 * previous validation errors should not generate
5784 * a new one here
5785 */
5786 ret = 1;
5787 }
5788 }
5789 }
5790 }
5791 vstateVPop(ctxt);
5792 }
5793 return(ret);
5794}
5795#endif /* LIBXML_REGEXP_ENABLED */
5796
5797/**
5798 * xmlValidateOneElement:
5799 * @ctxt: the validation context
5800 * @doc: a document instance
5801 * @elem: an element instance
5802 *
5803 * DEPRECATED: Internal function, don't use.
5804 *
5805 * Try to validate a single element and it's attributes,
5806 * basically it does the following checks as described by the
5807 * XML-1.0 recommendation:
5808 * - [ VC: Element Valid ]
5809 * - [ VC: Required Attribute ]
5810 * Then call xmlValidateOneAttribute() for each attribute present.
5811 *
5812 * The ID/IDREF checkings are done separately
5813 *
5814 * returns 1 if valid or 0 otherwise
5815 */
5816
5817int
5818xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5819 xmlNodePtr elem) {
5820 xmlElementPtr elemDecl = NULL;
5821 xmlElementContentPtr cont;
5822 xmlAttributePtr attr;
5823 xmlNodePtr child;
5824 int ret = 1, tmp;
5825 const xmlChar *name;
5826 int extsubset = 0;
5827
5828 CHECK_DTD;
5829
5830 if (elem == NULL) return(0);
5831 switch (elem->type) {
5832 case XML_TEXT_NODE:
5833 case XML_CDATA_SECTION_NODE:
5834 case XML_ENTITY_REF_NODE:
5835 case XML_PI_NODE:
5836 case XML_COMMENT_NODE:
5837 case XML_XINCLUDE_START:
5838 case XML_XINCLUDE_END:
5839 return(1);
5840 case XML_ELEMENT_NODE:
5841 break;
5842 default:
5843 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5844 "unexpected element type\n", NULL, NULL ,NULL);
5845 return(0);
5846 }
5847
5848 /*
5849 * Fetch the declaration
5850 */
5851 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5852 if (elemDecl == NULL)
5853 return(0);
5854
5855 /*
5856 * If vstateNr is not zero that means continuous validation is
5857 * activated, do not try to check the content model at that level.
5858 */
5859 if (ctxt->vstateNr == 0) {
5860 /* Check that the element content matches the definition */
5861 switch (elemDecl->etype) {
5862 case XML_ELEMENT_TYPE_UNDEFINED:
5863 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5864 "No declaration for element %s\n",
5865 elem->name, NULL, NULL);
5866 return(0);
5867 case XML_ELEMENT_TYPE_EMPTY:
5868 if (elem->children != NULL) {
5869 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
5870 "Element %s was declared EMPTY this one has content\n",
5871 elem->name, NULL, NULL);
5872 ret = 0;
5873 }
5874 break;
5875 case XML_ELEMENT_TYPE_ANY:
5876 /* I don't think anything is required then */
5877 break;
5878 case XML_ELEMENT_TYPE_MIXED:
5879
5880 /* simple case of declared as #PCDATA */
5881 if ((elemDecl->content != NULL) &&
5882 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5883 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5884 if (!ret) {
5885 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
5886 "Element %s was declared #PCDATA but contains non text nodes\n",
5887 elem->name, NULL, NULL);
5888 }
5889 break;
5890 }
5891 child = elem->children;
5892 /* Hum, this start to get messy */
5893 while (child != NULL) {
5894 if (child->type == XML_ELEMENT_NODE) {
5895 name = child->name;
5896 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
5897 xmlChar fn[50];
5898 xmlChar *fullname;
5899
5900 fullname = xmlBuildQName(child->name, child->ns->prefix,
5901 fn, 50);
5902 if (fullname == NULL) {
5903 xmlVErrMemory(ctxt);
5904 return(0);
5905 }
5906 cont = elemDecl->content;
5907 while (cont != NULL) {
5908 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5909 if (xmlStrEqual(cont->name, fullname))
5910 break;
5911 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5912 (cont->c1 != NULL) &&
5913 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5914 if (xmlStrEqual(cont->c1->name, fullname))
5915 break;
5916 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5917 (cont->c1 == NULL) ||
5918 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5919 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5920 "Internal: MIXED struct corrupted\n",
5921 NULL);
5922 break;
5923 }
5924 cont = cont->c2;
5925 }
5926 if ((fullname != fn) && (fullname != child->name))
5927 xmlFree(fullname);
5928 if (cont != NULL)
5929 goto child_ok;
5930 }
5931 cont = elemDecl->content;
5932 while (cont != NULL) {
5933 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5934 if (xmlStrEqual(cont->name, name)) break;
5935 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5936 (cont->c1 != NULL) &&
5937 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5938 if (xmlStrEqual(cont->c1->name, name)) break;
5939 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5940 (cont->c1 == NULL) ||
5941 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
5942 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5943 "Internal: MIXED struct corrupted\n",
5944 NULL);
5945 break;
5946 }
5947 cont = cont->c2;
5948 }
5949 if (cont == NULL) {
5950 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
5951 "Element %s is not declared in %s list of possible children\n",
5952 name, elem->name, NULL);
5953 ret = 0;
5954 }
5955 }
5956child_ok:
5957 child = child->next;
5958 }
5959 break;
5960 case XML_ELEMENT_TYPE_ELEMENT:
5961 if ((doc->standalone == 1) && (extsubset == 1)) {
5962 /*
5963 * VC: Standalone Document Declaration
5964 * - element types with element content, if white space
5965 * occurs directly within any instance of those types.
5966 */
5967 child = elem->children;
5968 while (child != NULL) {
5969 if ((child->type == XML_TEXT_NODE) &&
5970 (child->content != NULL)) {
5971 const xmlChar *content = child->content;
5972
5973 while (IS_BLANK_CH(*content))
5974 content++;
5975 if (*content == 0) {
5976 xmlErrValidNode(ctxt, elem,
5977 XML_DTD_STANDALONE_WHITE_SPACE,
5978"standalone: %s declared in the external subset contains white spaces nodes\n",
5979 elem->name, NULL, NULL);
5980 ret = 0;
5981 break;
5982 }
5983 }
5984 child =child->next;
5985 }
5986 }
5987 child = elem->children;
5988 cont = elemDecl->content;
5989 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
5990 if (tmp <= 0)
5991 ret = 0;
5992 break;
5993 }
5994 } /* not continuous */
5995
5996 /* [ VC: Required Attribute ] */
5997 attr = elemDecl->attributes;
5998 while (attr != NULL) {
5999 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6000 int qualified = -1;
6001
6002 if ((attr->prefix == NULL) &&
6003 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6004 xmlNsPtr ns;
6005
6006 ns = elem->nsDef;
6007 while (ns != NULL) {
6008 if (ns->prefix == NULL)
6009 goto found;
6010 ns = ns->next;
6011 }
6012 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6013 xmlNsPtr ns;
6014
6015 ns = elem->nsDef;
6016 while (ns != NULL) {
6017 if (xmlStrEqual(attr->name, ns->prefix))
6018 goto found;
6019 ns = ns->next;
6020 }
6021 } else {
6022 xmlAttrPtr attrib;
6023
6024 attrib = elem->properties;
6025 while (attrib != NULL) {
6026 if (xmlStrEqual(attrib->name, attr->name)) {
6027 if (attr->prefix != NULL) {
6028 xmlNsPtr nameSpace = attrib->ns;
6029
6030 if (nameSpace == NULL)
6031 nameSpace = elem->ns;
6032 /*
6033 * qualified names handling is problematic, having a
6034 * different prefix should be possible but DTDs don't
6035 * allow to define the URI instead of the prefix :-(
6036 */
6037 if (nameSpace == NULL) {
6038 if (qualified < 0)
6039 qualified = 0;
6040 } else if (!xmlStrEqual(nameSpace->prefix,
6041 attr->prefix)) {
6042 if (qualified < 1)
6043 qualified = 1;
6044 } else
6045 goto found;
6046 } else {
6047 /*
6048 * We should allow applications to define namespaces
6049 * for their application even if the DTD doesn't
6050 * carry one, otherwise, basically we would always
6051 * break.
6052 */
6053 goto found;
6054 }
6055 }
6056 attrib = attrib->next;
6057 }
6058 }
6059 if (qualified == -1) {
6060 if (attr->prefix == NULL) {
6061 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6062 "Element %s does not carry attribute %s\n",
6063 elem->name, attr->name, NULL);
6064 ret = 0;
6065 } else {
6066 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6067 "Element %s does not carry attribute %s:%s\n",
6068 elem->name, attr->prefix,attr->name);
6069 ret = 0;
6070 }
6071 } else if (qualified == 0) {
6072 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6073 "Element %s required attribute %s:%s has no prefix\n",
6074 elem->name, attr->prefix, attr->name);
6075 } else if (qualified == 1) {
6076 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6077 "Element %s required attribute %s:%s has different prefix\n",
6078 elem->name, attr->prefix, attr->name);
6079 }
6080 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6081 /*
6082 * Special tests checking #FIXED namespace declarations
6083 * have the right value since this is not done as an
6084 * attribute checking
6085 */
6086 if ((attr->prefix == NULL) &&
6087 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6088 xmlNsPtr ns;
6089
6090 ns = elem->nsDef;
6091 while (ns != NULL) {
6092 if (ns->prefix == NULL) {
6093 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6094 xmlErrValidNode(ctxt, elem,
6095 XML_DTD_ELEM_DEFAULT_NAMESPACE,
6096 "Element %s namespace name for default namespace does not match the DTD\n",
6097 elem->name, NULL, NULL);
6098 ret = 0;
6099 }
6100 goto found;
6101 }
6102 ns = ns->next;
6103 }
6104 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6105 xmlNsPtr ns;
6106
6107 ns = elem->nsDef;
6108 while (ns != NULL) {
6109 if (xmlStrEqual(attr->name, ns->prefix)) {
6110 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6111 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6112 "Element %s namespace name for %s does not match the DTD\n",
6113 elem->name, ns->prefix, NULL);
6114 ret = 0;
6115 }
6116 goto found;
6117 }
6118 ns = ns->next;
6119 }
6120 }
6121 }
6122found:
6123 attr = attr->nexth;
6124 }
6125 return(ret);
6126}
6127
6128/**
6129 * xmlValidateRoot:
6130 * @ctxt: the validation context
6131 * @doc: a document instance
6132 *
6133 * DEPRECATED: Internal function, don't use.
6134 *
6135 * Try to validate a the root element
6136 * basically it does the following check as described by the
6137 * XML-1.0 recommendation:
6138 * - [ VC: Root Element Type ]
6139 * it doesn't try to recurse or apply other check to the element
6140 *
6141 * returns 1 if valid or 0 otherwise
6142 */
6143
6144int
6145xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6146 xmlNodePtr root;
6147 int ret;
6148
6149 if (doc == NULL) return(0);
6150
6151 root = xmlDocGetRootElement(doc);
6152 if ((root == NULL) || (root->name == NULL)) {
6153 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6154 "no root element\n", NULL);
6155 return(0);
6156 }
6157
6158 /*
6159 * When doing post validation against a separate DTD, those may
6160 * no internal subset has been generated
6161 */
6162 if ((doc->intSubset != NULL) &&
6163 (doc->intSubset->name != NULL)) {
6164 /*
6165 * Check first the document root against the NQName
6166 */
6167 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6168 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6169 xmlChar fn[50];
6170 xmlChar *fullname;
6171
6172 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6173 if (fullname == NULL) {
6174 xmlVErrMemory(ctxt);
6175 return(0);
6176 }
6177 ret = xmlStrEqual(doc->intSubset->name, fullname);
6178 if ((fullname != fn) && (fullname != root->name))
6179 xmlFree(fullname);
6180 if (ret == 1)
6181 goto name_ok;
6182 }
6183 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6184 (xmlStrEqual(root->name, BAD_CAST "html")))
6185 goto name_ok;
6186 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6187 "root and DTD name do not match '%s' and '%s'\n",
6188 root->name, doc->intSubset->name, NULL);
6189 return(0);
6190 }
6191 }
6192name_ok:
6193 return(1);
6194}
6195
6196
6197/**
6198 * xmlValidateElement:
6199 * @ctxt: the validation context
6200 * @doc: a document instance
6201 * @root: an element instance
6202 *
6203 * Try to validate the subtree under an element
6204 *
6205 * returns 1 if valid or 0 otherwise
6206 */
6207
6208int
6209xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) {
6210 xmlNodePtr elem;
6211 xmlAttrPtr attr;
6212 xmlNsPtr ns;
6213 const xmlChar *value;
6214 int ret = 1;
6215
6216 if (root == NULL) return(0);
6217
6218 CHECK_DTD;
6219
6220 elem = root;
6221 while (1) {
6222 ret &= xmlValidateOneElement(ctxt, doc, elem);
6223
6224 if (elem->type == XML_ELEMENT_NODE) {
6225 attr = elem->properties;
6226 while (attr != NULL) {
6227 value = xmlNodeListGetString(doc, attr->children, 0);
6228 if (value == NULL) {
6229 xmlVErrMemory(ctxt);
6230 ret = 0;
6231 } else {
6232 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6233 xmlFree((char *)value);
6234 }
6235 attr= attr->next;
6236 }
6237
6238 ns = elem->nsDef;
6239 while (ns != NULL) {
6240 if (elem->ns == NULL)
6241 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6242 ns, ns->href);
6243 else
6244 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6245 elem->ns->prefix, ns,
6246 ns->href);
6247 ns = ns->next;
6248 }
6249
6250 if (elem->children != NULL) {
6251 elem = elem->children;
6252 continue;
6253 }
6254 }
6255
6256 while (1) {
6257 if (elem == root)
6258 goto done;
6259 if (elem->next != NULL)
6260 break;
6261 elem = elem->parent;
6262 }
6263 elem = elem->next;
6264 }
6265
6266done:
6267 return(ret);
6268}
6269
6270/**
6271 * xmlValidateRef:
6272 * @ref: A reference to be validated
6273 * @ctxt: Validation context
6274 * @name: Name of ID we are searching for
6275 *
6276 */
6277static void
6278xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
6279 const xmlChar *name) {
6280 xmlAttrPtr id;
6281 xmlAttrPtr attr;
6282
6283 if (ref == NULL)
6284 return;
6285 if ((ref->attr == NULL) && (ref->name == NULL))
6286 return;
6287 attr = ref->attr;
6288 if (attr == NULL) {
6289 xmlChar *dup, *str = NULL, *cur, save;
6290
6291 dup = xmlStrdup(name);
6292 if (dup == NULL) {
6293 xmlVErrMemory(ctxt);
6294 return;
6295 }
6296 cur = dup;
6297 while (*cur != 0) {
6298 str = cur;
6299 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6300 save = *cur;
6301 *cur = 0;
6302 id = xmlGetID(ctxt->doc, str);
6303 if (id == NULL) {
6304 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6305 "attribute %s line %d references an unknown ID \"%s\"\n",
6306 ref->name, ref->lineno, str);
6307 ctxt->valid = 0;
6308 }
6309 if (save == 0)
6310 break;
6311 *cur = save;
6312 while (IS_BLANK_CH(*cur)) cur++;
6313 }
6314 xmlFree(dup);
6315 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6316 id = xmlGetID(ctxt->doc, name);
6317 if (id == NULL) {
6318 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6319 "IDREF attribute %s references an unknown ID \"%s\"\n",
6320 attr->name, name, NULL);
6321 ctxt->valid = 0;
6322 }
6323 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6324 xmlChar *dup, *str = NULL, *cur, save;
6325
6326 dup = xmlStrdup(name);
6327 if (dup == NULL) {
6328 xmlVErrMemory(ctxt);
6329 ctxt->valid = 0;
6330 return;
6331 }
6332 cur = dup;
6333 while (*cur != 0) {
6334 str = cur;
6335 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6336 save = *cur;
6337 *cur = 0;
6338 id = xmlGetID(ctxt->doc, str);
6339 if (id == NULL) {
6340 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6341 "IDREFS attribute %s references an unknown ID \"%s\"\n",
6342 attr->name, str, NULL);
6343 ctxt->valid = 0;
6344 }
6345 if (save == 0)
6346 break;
6347 *cur = save;
6348 while (IS_BLANK_CH(*cur)) cur++;
6349 }
6350 xmlFree(dup);
6351 }
6352}
6353
6354/**
6355 * xmlWalkValidateList:
6356 * @data: Contents of current link
6357 * @user: Value supplied by the user
6358 *
6359 * Returns 0 to abort the walk or 1 to continue
6360 */
6361static int
6362xmlWalkValidateList(const void *data, void *user)
6363{
6364 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6365 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6366 return 1;
6367}
6368
6369/**
6370 * xmlValidateCheckRefCallback:
6371 * @ref_list: List of references
6372 * @ctxt: Validation context
6373 * @name: Name of ID we are searching for
6374 *
6375 */
6376static void
6377xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) {
6378 xmlListPtr ref_list = (xmlListPtr) payload;
6379 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6380 xmlValidateMemo memo;
6381
6382 if (ref_list == NULL)
6383 return;
6384 memo.ctxt = ctxt;
6385 memo.name = name;
6386
6387 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6388
6389}
6390
6391/**
6392 * xmlValidateDocumentFinal:
6393 * @ctxt: the validation context
6394 * @doc: a document instance
6395 *
6396 * DEPRECATED: Internal function, don't use.
6397 *
6398 * Does the final step for the document validation once all the
6399 * incremental validation steps have been completed
6400 *
6401 * basically it does the following checks described by the XML Rec
6402 *
6403 * Check all the IDREF/IDREFS attributes definition for validity
6404 *
6405 * returns 1 if valid or 0 otherwise
6406 */
6407
6408int
6409xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6410 xmlRefTablePtr table;
6411 xmlParserCtxtPtr pctxt = NULL;
6412 xmlParserInputPtr oldInput = NULL;
6413
6414 if (ctxt == NULL)
6415 return(0);
6416 if (doc == NULL) {
6417 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6418 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
6419 return(0);
6420 }
6421
6422 /*
6423 * Check all the NOTATION/NOTATIONS attributes
6424 */
6425 /*
6426 * Check all the ENTITY/ENTITIES attributes definition for validity
6427 */
6428 /*
6429 * Check all the IDREF/IDREFS attributes definition for validity
6430 */
6431
6432 /*
6433 * Don't print line numbers.
6434 */
6435 if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
6436 pctxt = ctxt->userData;
6437 oldInput = pctxt->input;
6438 pctxt->input = NULL;
6439 }
6440
6441 table = (xmlRefTablePtr) doc->refs;
6442 ctxt->doc = doc;
6443 ctxt->valid = 1;
6444 xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
6445
6446 if (ctxt->flags & XML_VCTXT_USE_PCTXT)
6447 pctxt->input = oldInput;
6448
6449 return(ctxt->valid);
6450}
6451
6452/**
6453 * xmlValidateDtd:
6454 * @ctxt: the validation context
6455 * @doc: a document instance
6456 * @dtd: a dtd instance
6457 *
6458 * Try to validate the document against the dtd instance
6459 *
6460 * Basically it does check all the definitions in the DtD.
6461 * Note the the internal subset (if present) is de-coupled
6462 * (i.e. not used), which could give problems if ID or IDREF
6463 * is present.
6464 *
6465 * returns 1 if valid or 0 otherwise
6466 */
6467
6468int
6469xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6470 int ret;
6471 xmlDtdPtr oldExt, oldInt;
6472 xmlNodePtr root;
6473
6474 if (dtd == NULL)
6475 return(0);
6476 if (doc == NULL)
6477 return(0);
6478
6479 oldExt = doc->extSubset;
6480 oldInt = doc->intSubset;
6481 doc->extSubset = dtd;
6482 doc->intSubset = NULL;
6483 if (doc->ids != NULL) {
6484 xmlFreeIDTable(doc->ids);
6485 doc->ids = NULL;
6486 }
6487 if (doc->refs != NULL) {
6488 xmlFreeRefTable(doc->refs);
6489 doc->refs = NULL;
6490 }
6491
6492 ret = xmlValidateRoot(ctxt, doc);
6493 if (ret != 0) {
6494 root = xmlDocGetRootElement(doc);
6495 ret = xmlValidateElement(ctxt, doc, root);
6496 ret &= xmlValidateDocumentFinal(ctxt, doc);
6497 }
6498
6499 doc->extSubset = oldExt;
6500 doc->intSubset = oldInt;
6501 if (doc->ids != NULL) {
6502 xmlFreeIDTable(doc->ids);
6503 doc->ids = NULL;
6504 }
6505 if (doc->refs != NULL) {
6506 xmlFreeRefTable(doc->refs);
6507 doc->refs = NULL;
6508 }
6509
6510 return(ret);
6511}
6512
6513static void
6514xmlValidateNotationCallback(void *payload, void *data,
6515 const xmlChar *name ATTRIBUTE_UNUSED) {
6516 xmlEntityPtr cur = (xmlEntityPtr) payload;
6517 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6518 if (cur == NULL)
6519 return;
6520 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6521 xmlChar *notation = cur->content;
6522
6523 if (notation != NULL) {
6524 int ret;
6525
6526 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6527 if (ret != 1) {
6528 ctxt->valid = 0;
6529 }
6530 }
6531 }
6532}
6533
6534static void
6535xmlValidateAttributeCallback(void *payload, void *data,
6536 const xmlChar *name ATTRIBUTE_UNUSED) {
6537 xmlAttributePtr cur = (xmlAttributePtr) payload;
6538 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6539 int ret;
6540 xmlDocPtr doc;
6541 xmlElementPtr elem = NULL;
6542
6543 if (cur == NULL)
6544 return;
6545 switch (cur->atype) {
6546 case XML_ATTRIBUTE_CDATA:
6547 case XML_ATTRIBUTE_ID:
6548 case XML_ATTRIBUTE_IDREF :
6549 case XML_ATTRIBUTE_IDREFS:
6550 case XML_ATTRIBUTE_NMTOKEN:
6551 case XML_ATTRIBUTE_NMTOKENS:
6552 case XML_ATTRIBUTE_ENUMERATION:
6553 break;
6554 case XML_ATTRIBUTE_ENTITY:
6555 case XML_ATTRIBUTE_ENTITIES:
6556 case XML_ATTRIBUTE_NOTATION:
6557 if (cur->defaultValue != NULL) {
6558
6559 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6560 cur->atype, cur->defaultValue);
6561 if ((ret == 0) && (ctxt->valid == 1))
6562 ctxt->valid = 0;
6563 }
6564 if (cur->tree != NULL) {
6565 xmlEnumerationPtr tree = cur->tree;
6566 while (tree != NULL) {
6567 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6568 cur->name, cur->atype, tree->name);
6569 if ((ret == 0) && (ctxt->valid == 1))
6570 ctxt->valid = 0;
6571 tree = tree->next;
6572 }
6573 }
6574 }
6575 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6576 const xmlChar *elemLocalName;
6577 xmlChar *elemPrefix;
6578
6579 doc = cur->doc;
6580 if (cur->elem == NULL) {
6581 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
6582 "xmlValidateAttributeCallback(%s): internal error\n",
6583 (const char *) cur->name);
6584 return;
6585 }
6586
6587 elemLocalName = xmlSplitQName4(cur->elem, &elemPrefix);
6588 if (elemLocalName == NULL) {
6589 xmlVErrMemory(ctxt);
6590 return;
6591 }
6592
6593 if ((doc != NULL) && (doc->intSubset != NULL))
6594 elem = xmlHashLookup2(doc->intSubset->elements,
6595 elemLocalName, elemPrefix);
6596 if ((elem == NULL) && (doc != NULL) && (doc->extSubset != NULL))
6597 elem = xmlHashLookup2(doc->extSubset->elements,
6598 elemLocalName, elemPrefix);
6599 if ((elem == NULL) && (cur->parent != NULL) &&
6600 (cur->parent->type == XML_DTD_NODE))
6601 elem = xmlHashLookup2(((xmlDtdPtr) cur->parent)->elements,
6602 elemLocalName, elemPrefix);
6603
6604 xmlFree(elemPrefix);
6605
6606 if (elem == NULL) {
6607 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
6608 "attribute %s: could not find decl for element %s\n",
6609 cur->name, cur->elem, NULL);
6610 return;
6611 }
6612 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6613 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6614 "NOTATION attribute %s declared for EMPTY element %s\n",
6615 cur->name, cur->elem, NULL);
6616 ctxt->valid = 0;
6617 }
6618 }
6619}
6620
6621/**
6622 * xmlValidateDtdFinal:
6623 * @ctxt: the validation context
6624 * @doc: a document instance
6625 *
6626 * DEPRECATED: Internal function, don't use.
6627 *
6628 * Does the final step for the dtds validation once all the
6629 * subsets have been parsed
6630 *
6631 * basically it does the following checks described by the XML Rec
6632 * - check that ENTITY and ENTITIES type attributes default or
6633 * possible values matches one of the defined entities.
6634 * - check that NOTATION type attributes default or
6635 * possible values matches one of the defined notations.
6636 *
6637 * returns 1 if valid or 0 if invalid and -1 if not well-formed
6638 */
6639
6640int
6641xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6642 xmlDtdPtr dtd;
6643 xmlAttributeTablePtr table;
6644 xmlEntitiesTablePtr entities;
6645
6646 if ((doc == NULL) || (ctxt == NULL)) return(0);
6647 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6648 return(0);
6649 ctxt->doc = doc;
6650 ctxt->valid = 1;
6651 dtd = doc->intSubset;
6652 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6653 table = (xmlAttributeTablePtr) dtd->attributes;
6654 xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6655 }
6656 if ((dtd != NULL) && (dtd->entities != NULL)) {
6657 entities = (xmlEntitiesTablePtr) dtd->entities;
6658 xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6659 }
6660 dtd = doc->extSubset;
6661 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6662 table = (xmlAttributeTablePtr) dtd->attributes;
6663 xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6664 }
6665 if ((dtd != NULL) && (dtd->entities != NULL)) {
6666 entities = (xmlEntitiesTablePtr) dtd->entities;
6667 xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6668 }
6669 return(ctxt->valid);
6670}
6671
6672/**
6673 * xmlValidateDocument:
6674 * @ctxt: the validation context
6675 * @doc: a document instance
6676 *
6677 * Try to validate the document instance
6678 *
6679 * basically it does the all the checks described by the XML Rec
6680 * i.e. validates the internal and external subset (if present)
6681 * and validate the document tree.
6682 *
6683 * returns 1 if valid or 0 otherwise
6684 */
6685
6686int
6687xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6688 int ret;
6689 xmlNodePtr root;
6690
6691 if (doc == NULL)
6692 return(0);
6693 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6694 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6695 "no DTD found!\n", NULL);
6696 return(0);
6697 }
6698 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6699 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6700 xmlChar *sysID;
6701 if (doc->intSubset->SystemID != NULL) {
6702 sysID = xmlBuildURI(doc->intSubset->SystemID,
6703 doc->URL);
6704 if (sysID == NULL) {
6705 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6706 "Could not build URI for external subset \"%s\"\n",
6707 (const char *) doc->intSubset->SystemID);
6708 return 0;
6709 }
6710 } else
6711 sysID = NULL;
6712 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6713 (const xmlChar *)sysID);
6714 if (sysID != NULL)
6715 xmlFree(sysID);
6716 if (doc->extSubset == NULL) {
6717 if (doc->intSubset->SystemID != NULL) {
6718 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6719 "Could not load the external subset \"%s\"\n",
6720 (const char *) doc->intSubset->SystemID);
6721 } else {
6722 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6723 "Could not load the external subset \"%s\"\n",
6724 (const char *) doc->intSubset->ExternalID);
6725 }
6726 return(0);
6727 }
6728 }
6729
6730 if (doc->ids != NULL) {
6731 xmlFreeIDTable(doc->ids);
6732 doc->ids = NULL;
6733 }
6734 if (doc->refs != NULL) {
6735 xmlFreeRefTable(doc->refs);
6736 doc->refs = NULL;
6737 }
6738 ret = xmlValidateDtdFinal(ctxt, doc);
6739 if (!xmlValidateRoot(ctxt, doc)) return(0);
6740
6741 root = xmlDocGetRootElement(doc);
6742 ret &= xmlValidateElement(ctxt, doc, root);
6743 ret &= xmlValidateDocumentFinal(ctxt, doc);
6744 return(ret);
6745}
6746
6747/************************************************************************
6748 * *
6749 * Routines for dynamic validation editing *
6750 * *
6751 ************************************************************************/
6752
6753/**
6754 * xmlValidGetPotentialChildren:
6755 * @ctree: an element content tree
6756 * @names: an array to store the list of child names
6757 * @len: a pointer to the number of element in the list
6758 * @max: the size of the array
6759 *
6760 * Build/extend a list of potential children allowed by the content tree
6761 *
6762 * returns the number of element in the list, or -1 in case of error.
6763 */
6764
6765int
6766xmlValidGetPotentialChildren(xmlElementContent *ctree,
6767 const xmlChar **names,
6768 int *len, int max) {
6769 int i;
6770
6771 if ((ctree == NULL) || (names == NULL) || (len == NULL))
6772 return(-1);
6773 if (*len >= max) return(*len);
6774
6775 switch (ctree->type) {
6776 case XML_ELEMENT_CONTENT_PCDATA:
6777 for (i = 0; i < *len;i++)
6778 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6779 names[(*len)++] = BAD_CAST "#PCDATA";
6780 break;
6781 case XML_ELEMENT_CONTENT_ELEMENT:
6782 for (i = 0; i < *len;i++)
6783 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6784 names[(*len)++] = ctree->name;
6785 break;
6786 case XML_ELEMENT_CONTENT_SEQ:
6787 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6788 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6789 break;
6790 case XML_ELEMENT_CONTENT_OR:
6791 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6792 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6793 break;
6794 }
6795
6796 return(*len);
6797}
6798
6799/*
6800 * Dummy function to suppress messages while we try out valid elements
6801 */
6802static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6803 const char *msg ATTRIBUTE_UNUSED, ...) {
6804 return;
6805}
6806
6807/**
6808 * xmlValidGetValidElements:
6809 * @prev: an element to insert after
6810 * @next: an element to insert next
6811 * @names: an array to store the list of child names
6812 * @max: the size of the array
6813 *
6814 * This function returns the list of authorized children to insert
6815 * within an existing tree while respecting the validity constraints
6816 * forced by the Dtd. The insertion point is defined using @prev and
6817 * @next in the following ways:
6818 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6819 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6820 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6821 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6822 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6823 *
6824 * pointers to the element names are inserted at the beginning of the array
6825 * and do not need to be freed.
6826 *
6827 * returns the number of element in the list, or -1 in case of error. If
6828 * the function returns the value @max the caller is invited to grow the
6829 * receiving array and retry.
6830 */
6831
6832int
6833xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
6834 int max) {
6835 xmlValidCtxt vctxt;
6836 int nb_valid_elements = 0;
6837 const xmlChar *elements[256]={0};
6838 int nb_elements = 0, i;
6839 const xmlChar *name;
6840
6841 xmlNode *ref_node;
6842 xmlNode *parent;
6843 xmlNode *test_node;
6844
6845 xmlNode *prev_next;
6846 xmlNode *next_prev;
6847 xmlNode *parent_childs;
6848 xmlNode *parent_last;
6849
6850 xmlElement *element_desc;
6851
6852 if (prev == NULL && next == NULL)
6853 return(-1);
6854
6855 if (names == NULL) return(-1);
6856 if (max <= 0) return(-1);
6857
6858 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6859 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6860
6861 nb_valid_elements = 0;
6862 ref_node = prev ? prev : next;
6863 parent = ref_node->parent;
6864
6865 /*
6866 * Retrieves the parent element declaration
6867 */
6868 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6869 parent->name);
6870 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6871 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6872 parent->name);
6873 if (element_desc == NULL) return(-1);
6874
6875 /*
6876 * Do a backup of the current tree structure
6877 */
6878 prev_next = prev ? prev->next : NULL;
6879 next_prev = next ? next->prev : NULL;
6880 parent_childs = parent->children;
6881 parent_last = parent->last;
6882
6883 /*
6884 * Creates a dummy node and insert it into the tree
6885 */
6886 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
6887 if (test_node == NULL)
6888 return(-1);
6889
6890 test_node->parent = parent;
6891 test_node->prev = prev;
6892 test_node->next = next;
6893 name = test_node->name;
6894
6895 if (prev) prev->next = test_node;
6896 else parent->children = test_node;
6897
6898 if (next) next->prev = test_node;
6899 else parent->last = test_node;
6900
6901 /*
6902 * Insert each potential child node and check if the parent is
6903 * still valid
6904 */
6905 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6906 elements, &nb_elements, 256);
6907
6908 for (i = 0;i < nb_elements;i++) {
6909 test_node->name = elements[i];
6910 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
6911 int j;
6912
6913 for (j = 0; j < nb_valid_elements;j++)
6914 if (xmlStrEqual(elements[i], names[j])) break;
6915 names[nb_valid_elements++] = elements[i];
6916 if (nb_valid_elements >= max) break;
6917 }
6918 }
6919
6920 /*
6921 * Restore the tree structure
6922 */
6923 if (prev) prev->next = prev_next;
6924 if (next) next->prev = next_prev;
6925 parent->children = parent_childs;
6926 parent->last = parent_last;
6927
6928 /*
6929 * Free up the dummy node
6930 */
6931 test_node->name = name;
6932 xmlFreeNode(test_node);
6933
6934 return(nb_valid_elements);
6935}
6936#endif /* LIBXML_VALID_ENABLED */
6937
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette