VirtualBox

source: vbox/trunk/src/libs/libxml2-2.6.31/valid.c@ 55391

最後變更 在這個檔案從55391是 39915,由 vboxsync 提交於 13 年 前

libxml-2.6.31 unmodified

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

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