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