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