a64b96be956aa93c6ce2e67a7f87325a1ca7fad0
[reactos.git] / sdk / lib / 3rdparty / libxml2 / valid.c
1 /*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * daniel@veillard.com
8 */
9
10 #define IN_LIBXML
11 #include "libxml.h"
12
13 #include <string.h>
14
15 #ifdef HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18
19 #include <libxml/xmlmemory.h>
20 #include <libxml/hash.h>
21 #include <libxml/uri.h>
22 #include <libxml/valid.h>
23 #include <libxml/parser.h>
24 #include <libxml/parserInternals.h>
25 #include <libxml/xmlerror.h>
26 #include <libxml/list.h>
27 #include <libxml/globals.h>
28
29 static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
30 int create);
31 /* #define DEBUG_VALID_ALGO */
32 /* #define DEBUG_REGEXP_ALGO */
33
34 #define TODO \
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
37 __FILE__, __LINE__);
38
39 #ifdef LIBXML_VALID_ENABLED
40 static int
41 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
42 const xmlChar *value);
43 #endif
44 /************************************************************************
45 * *
46 * Error handling routines *
47 * *
48 ************************************************************************/
49
50 /**
51 * xmlVErrMemory:
52 * @ctxt: an XML validation parser context
53 * @extra: extra informations
54 *
55 * Handle an out of memory error
56 */
57 static void
58 xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
59 {
60 xmlGenericErrorFunc channel = NULL;
61 xmlParserCtxtPtr pctxt = NULL;
62 void *data = NULL;
63
64 if (ctxt != NULL) {
65 channel = ctxt->error;
66 data = ctxt->userData;
67 /* Use the special values to detect if it is part of a parsing
68 context */
69 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
70 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
71 long delta = (char *) ctxt - (char *) ctxt->userData;
72 if ((delta > 0) && (delta < 250))
73 pctxt = ctxt->userData;
74 }
75 }
76 if (extra)
77 __xmlRaiseError(NULL, channel, data,
78 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
79 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
80 "Memory allocation failed : %s\n", extra);
81 else
82 __xmlRaiseError(NULL, channel, data,
83 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
84 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
85 "Memory allocation failed\n");
86 }
87
88 /**
89 * xmlErrValid:
90 * @ctxt: an XML validation parser context
91 * @error: the error number
92 * @extra: extra informations
93 *
94 * Handle a validation error
95 */
96 static void LIBXML_ATTR_FORMAT(3,0)
97 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
98 const char *msg, const char *extra)
99 {
100 xmlGenericErrorFunc channel = NULL;
101 xmlParserCtxtPtr pctxt = NULL;
102 void *data = NULL;
103
104 if (ctxt != NULL) {
105 channel = ctxt->error;
106 data = ctxt->userData;
107 /* Use the special values to detect if it is part of a parsing
108 context */
109 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
110 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
111 long delta = (char *) ctxt - (char *) ctxt->userData;
112 if ((delta > 0) && (delta < 250))
113 pctxt = ctxt->userData;
114 }
115 }
116 if (extra)
117 __xmlRaiseError(NULL, channel, data,
118 pctxt, NULL, XML_FROM_VALID, error,
119 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
120 msg, extra);
121 else
122 __xmlRaiseError(NULL, channel, data,
123 pctxt, NULL, XML_FROM_VALID, error,
124 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
125 "%s", msg);
126 }
127
128 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
129 /**
130 * xmlErrValidNode:
131 * @ctxt: an XML validation parser context
132 * @node: the node raising the error
133 * @error: the error number
134 * @str1: extra informations
135 * @str2: extra informations
136 * @str3: extra informations
137 *
138 * Handle a validation error, provide contextual informations
139 */
140 static void LIBXML_ATTR_FORMAT(4,0)
141 xmlErrValidNode(xmlValidCtxtPtr ctxt,
142 xmlNodePtr node, xmlParserErrors error,
143 const char *msg, const xmlChar * str1,
144 const xmlChar * str2, const xmlChar * str3)
145 {
146 xmlStructuredErrorFunc schannel = NULL;
147 xmlGenericErrorFunc channel = NULL;
148 xmlParserCtxtPtr pctxt = NULL;
149 void *data = NULL;
150
151 if (ctxt != NULL) {
152 channel = ctxt->error;
153 data = ctxt->userData;
154 /* Use the special values to detect if it is part of a parsing
155 context */
156 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
157 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
158 long delta = (char *) ctxt - (char *) ctxt->userData;
159 if ((delta > 0) && (delta < 250))
160 pctxt = ctxt->userData;
161 }
162 }
163 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
164 XML_ERR_ERROR, NULL, 0,
165 (const char *) str1,
166 (const char *) str2,
167 (const char *) str3, 0, 0, msg, str1, str2, str3);
168 }
169 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
170
171 #ifdef LIBXML_VALID_ENABLED
172 /**
173 * xmlErrValidNodeNr:
174 * @ctxt: an XML validation parser context
175 * @node: the node raising the error
176 * @error: the error number
177 * @str1: extra informations
178 * @int2: extra informations
179 * @str3: extra informations
180 *
181 * Handle a validation error, provide contextual informations
182 */
183 static void LIBXML_ATTR_FORMAT(4,0)
184 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
185 xmlNodePtr node, xmlParserErrors error,
186 const char *msg, const xmlChar * str1,
187 int int2, const xmlChar * str3)
188 {
189 xmlStructuredErrorFunc schannel = NULL;
190 xmlGenericErrorFunc channel = NULL;
191 xmlParserCtxtPtr pctxt = NULL;
192 void *data = NULL;
193
194 if (ctxt != NULL) {
195 channel = ctxt->error;
196 data = ctxt->userData;
197 /* Use the special values to detect if it is part of a parsing
198 context */
199 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
200 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
201 long delta = (char *) ctxt - (char *) ctxt->userData;
202 if ((delta > 0) && (delta < 250))
203 pctxt = ctxt->userData;
204 }
205 }
206 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
207 XML_ERR_ERROR, NULL, 0,
208 (const char *) str1,
209 (const char *) str3,
210 NULL, int2, 0, msg, str1, int2, str3);
211 }
212
213 /**
214 * xmlErrValidWarning:
215 * @ctxt: an XML validation parser context
216 * @node: the node raising the error
217 * @error: the error number
218 * @str1: extra information
219 * @str2: extra information
220 * @str3: extra information
221 *
222 * Handle a validation error, provide contextual information
223 */
224 static void LIBXML_ATTR_FORMAT(4,0)
225 xmlErrValidWarning(xmlValidCtxtPtr ctxt,
226 xmlNodePtr node, xmlParserErrors error,
227 const char *msg, const xmlChar * str1,
228 const xmlChar * str2, const xmlChar * str3)
229 {
230 xmlStructuredErrorFunc schannel = NULL;
231 xmlGenericErrorFunc channel = NULL;
232 xmlParserCtxtPtr pctxt = NULL;
233 void *data = NULL;
234
235 if (ctxt != NULL) {
236 channel = ctxt->warning;
237 data = ctxt->userData;
238 /* Use the special values to detect if it is part of a parsing
239 context */
240 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
241 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
242 long delta = (char *) ctxt - (char *) ctxt->userData;
243 if ((delta > 0) && (delta < 250))
244 pctxt = ctxt->userData;
245 }
246 }
247 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
248 XML_ERR_WARNING, NULL, 0,
249 (const char *) str1,
250 (const char *) str2,
251 (const char *) str3, 0, 0, msg, str1, str2, str3);
252 }
253
254
255
256 #ifdef LIBXML_REGEXP_ENABLED
257 /*
258 * If regexp are enabled we can do continuous validation without the
259 * need of a tree to validate the content model. this is done in each
260 * callbacks.
261 * Each xmlValidState represent the validation state associated to the
262 * set of nodes currently open from the document root to the current element.
263 */
264
265
266 typedef struct _xmlValidState {
267 xmlElementPtr elemDecl; /* pointer to the content model */
268 xmlNodePtr node; /* pointer to the current node */
269 xmlRegExecCtxtPtr exec; /* regexp runtime */
270 } _xmlValidState;
271
272
273 static int
274 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
275 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
276 ctxt->vstateMax = 10;
277 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
278 sizeof(ctxt->vstateTab[0]));
279 if (ctxt->vstateTab == NULL) {
280 xmlVErrMemory(ctxt, "malloc failed");
281 return(-1);
282 }
283 }
284
285 if (ctxt->vstateNr >= ctxt->vstateMax) {
286 xmlValidState *tmp;
287
288 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
289 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
290 if (tmp == NULL) {
291 xmlVErrMemory(ctxt, "realloc failed");
292 return(-1);
293 }
294 ctxt->vstateMax *= 2;
295 ctxt->vstateTab = tmp;
296 }
297 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
298 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
299 ctxt->vstateTab[ctxt->vstateNr].node = node;
300 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
301 if (elemDecl->contModel == NULL)
302 xmlValidBuildContentModel(ctxt, elemDecl);
303 if (elemDecl->contModel != NULL) {
304 ctxt->vstateTab[ctxt->vstateNr].exec =
305 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
306 } else {
307 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
308 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
309 XML_ERR_INTERNAL_ERROR,
310 "Failed to build content model regexp for %s\n",
311 node->name, NULL, NULL);
312 }
313 }
314 return(ctxt->vstateNr++);
315 }
316
317 static int
318 vstateVPop(xmlValidCtxtPtr ctxt) {
319 xmlElementPtr elemDecl;
320
321 if (ctxt->vstateNr < 1) return(-1);
322 ctxt->vstateNr--;
323 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
324 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
325 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
326 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
327 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
328 }
329 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
330 if (ctxt->vstateNr >= 1)
331 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
332 else
333 ctxt->vstate = NULL;
334 return(ctxt->vstateNr);
335 }
336
337 #else /* not LIBXML_REGEXP_ENABLED */
338 /*
339 * If regexp are not enabled, it uses a home made algorithm less
340 * complex and easier to
341 * debug/maintain than a generic NFA -> DFA state based algo. The
342 * only restriction is on the deepness of the tree limited by the
343 * size of the occurs bitfield
344 *
345 * this is the content of a saved state for rollbacks
346 */
347
348 #define ROLLBACK_OR 0
349 #define ROLLBACK_PARENT 1
350
351 typedef struct _xmlValidState {
352 xmlElementContentPtr cont; /* pointer to the content model subtree */
353 xmlNodePtr node; /* pointer to the current node in the list */
354 long occurs;/* bitfield for multiple occurrences */
355 unsigned char depth; /* current depth in the overall tree */
356 unsigned char state; /* ROLLBACK_XXX */
357 } _xmlValidState;
358
359 #define MAX_RECURSE 25000
360 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361 #define CONT ctxt->vstate->cont
362 #define NODE ctxt->vstate->node
363 #define DEPTH ctxt->vstate->depth
364 #define OCCURS ctxt->vstate->occurs
365 #define STATE ctxt->vstate->state
366
367 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
369
370 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
372
373 static int
374 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
375 xmlNodePtr node, unsigned char depth, long occurs,
376 unsigned char state) {
377 int i = ctxt->vstateNr - 1;
378
379 if (ctxt->vstateNr > MAX_RECURSE) {
380 return(-1);
381 }
382 if (ctxt->vstateTab == NULL) {
383 ctxt->vstateMax = 8;
384 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
385 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
386 if (ctxt->vstateTab == NULL) {
387 xmlVErrMemory(ctxt, "malloc failed");
388 return(-1);
389 }
390 }
391 if (ctxt->vstateNr >= ctxt->vstateMax) {
392 xmlValidState *tmp;
393
394 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
395 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
396 if (tmp == NULL) {
397 xmlVErrMemory(ctxt, "malloc failed");
398 return(-1);
399 }
400 ctxt->vstateMax *= 2;
401 ctxt->vstateTab = tmp;
402 ctxt->vstate = &ctxt->vstateTab[0];
403 }
404 /*
405 * Don't push on the stack a state already here
406 */
407 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
408 (ctxt->vstateTab[i].node == node) &&
409 (ctxt->vstateTab[i].depth == depth) &&
410 (ctxt->vstateTab[i].occurs == occurs) &&
411 (ctxt->vstateTab[i].state == state))
412 return(ctxt->vstateNr);
413 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
414 ctxt->vstateTab[ctxt->vstateNr].node = node;
415 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
416 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
417 ctxt->vstateTab[ctxt->vstateNr].state = state;
418 return(ctxt->vstateNr++);
419 }
420
421 static int
422 vstateVPop(xmlValidCtxtPtr ctxt) {
423 if (ctxt->vstateNr <= 1) return(-1);
424 ctxt->vstateNr--;
425 ctxt->vstate = &ctxt->vstateTab[0];
426 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
427 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
428 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
429 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
430 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
431 return(ctxt->vstateNr);
432 }
433
434 #endif /* LIBXML_REGEXP_ENABLED */
435
436 static int
437 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
438 {
439 if (ctxt->nodeMax <= 0) {
440 ctxt->nodeMax = 4;
441 ctxt->nodeTab =
442 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
443 sizeof(ctxt->nodeTab[0]));
444 if (ctxt->nodeTab == NULL) {
445 xmlVErrMemory(ctxt, "malloc failed");
446 ctxt->nodeMax = 0;
447 return (0);
448 }
449 }
450 if (ctxt->nodeNr >= ctxt->nodeMax) {
451 xmlNodePtr *tmp;
452 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
453 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
454 if (tmp == NULL) {
455 xmlVErrMemory(ctxt, "realloc failed");
456 return (0);
457 }
458 ctxt->nodeMax *= 2;
459 ctxt->nodeTab = tmp;
460 }
461 ctxt->nodeTab[ctxt->nodeNr] = value;
462 ctxt->node = value;
463 return (ctxt->nodeNr++);
464 }
465 static xmlNodePtr
466 nodeVPop(xmlValidCtxtPtr ctxt)
467 {
468 xmlNodePtr ret;
469
470 if (ctxt->nodeNr <= 0)
471 return (NULL);
472 ctxt->nodeNr--;
473 if (ctxt->nodeNr > 0)
474 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
475 else
476 ctxt->node = NULL;
477 ret = ctxt->nodeTab[ctxt->nodeNr];
478 ctxt->nodeTab[ctxt->nodeNr] = NULL;
479 return (ret);
480 }
481
482 #ifdef DEBUG_VALID_ALGO
483 static void
484 xmlValidPrintNode(xmlNodePtr cur) {
485 if (cur == NULL) {
486 xmlGenericError(xmlGenericErrorContext, "null");
487 return;
488 }
489 switch (cur->type) {
490 case XML_ELEMENT_NODE:
491 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
492 break;
493 case XML_TEXT_NODE:
494 xmlGenericError(xmlGenericErrorContext, "text ");
495 break;
496 case XML_CDATA_SECTION_NODE:
497 xmlGenericError(xmlGenericErrorContext, "cdata ");
498 break;
499 case XML_ENTITY_REF_NODE:
500 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
501 break;
502 case XML_PI_NODE:
503 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
504 break;
505 case XML_COMMENT_NODE:
506 xmlGenericError(xmlGenericErrorContext, "comment ");
507 break;
508 case XML_ATTRIBUTE_NODE:
509 xmlGenericError(xmlGenericErrorContext, "?attr? ");
510 break;
511 case XML_ENTITY_NODE:
512 xmlGenericError(xmlGenericErrorContext, "?ent? ");
513 break;
514 case XML_DOCUMENT_NODE:
515 xmlGenericError(xmlGenericErrorContext, "?doc? ");
516 break;
517 case XML_DOCUMENT_TYPE_NODE:
518 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
519 break;
520 case XML_DOCUMENT_FRAG_NODE:
521 xmlGenericError(xmlGenericErrorContext, "?frag? ");
522 break;
523 case XML_NOTATION_NODE:
524 xmlGenericError(xmlGenericErrorContext, "?nota? ");
525 break;
526 case XML_HTML_DOCUMENT_NODE:
527 xmlGenericError(xmlGenericErrorContext, "?html? ");
528 break;
529 #ifdef LIBXML_DOCB_ENABLED
530 case XML_DOCB_DOCUMENT_NODE:
531 xmlGenericError(xmlGenericErrorContext, "?docb? ");
532 break;
533 #endif
534 case XML_DTD_NODE:
535 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
536 break;
537 case XML_ELEMENT_DECL:
538 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
539 break;
540 case XML_ATTRIBUTE_DECL:
541 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
542 break;
543 case XML_ENTITY_DECL:
544 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
545 break;
546 case XML_NAMESPACE_DECL:
547 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
548 break;
549 case XML_XINCLUDE_START:
550 xmlGenericError(xmlGenericErrorContext, "incstart ");
551 break;
552 case XML_XINCLUDE_END:
553 xmlGenericError(xmlGenericErrorContext, "incend ");
554 break;
555 }
556 }
557
558 static void
559 xmlValidPrintNodeList(xmlNodePtr cur) {
560 if (cur == NULL)
561 xmlGenericError(xmlGenericErrorContext, "null ");
562 while (cur != NULL) {
563 xmlValidPrintNode(cur);
564 cur = cur->next;
565 }
566 }
567
568 static void
569 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
570 char expr[5000];
571
572 expr[0] = 0;
573 xmlGenericError(xmlGenericErrorContext, "valid: ");
574 xmlValidPrintNodeList(cur);
575 xmlGenericError(xmlGenericErrorContext, "against ");
576 xmlSnprintfElementContent(expr, 5000, cont, 1);
577 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
578 }
579
580 static void
581 xmlValidDebugState(xmlValidStatePtr state) {
582 xmlGenericError(xmlGenericErrorContext, "(");
583 if (state->cont == NULL)
584 xmlGenericError(xmlGenericErrorContext, "null,");
585 else
586 switch (state->cont->type) {
587 case XML_ELEMENT_CONTENT_PCDATA:
588 xmlGenericError(xmlGenericErrorContext, "pcdata,");
589 break;
590 case XML_ELEMENT_CONTENT_ELEMENT:
591 xmlGenericError(xmlGenericErrorContext, "%s,",
592 state->cont->name);
593 break;
594 case XML_ELEMENT_CONTENT_SEQ:
595 xmlGenericError(xmlGenericErrorContext, "seq,");
596 break;
597 case XML_ELEMENT_CONTENT_OR:
598 xmlGenericError(xmlGenericErrorContext, "or,");
599 break;
600 }
601 xmlValidPrintNode(state->node);
602 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
603 state->depth, state->occurs, state->state);
604 }
605
606 static void
607 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
608 int i, j;
609
610 xmlGenericError(xmlGenericErrorContext, "state: ");
611 xmlValidDebugState(ctxt->vstate);
612 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
613 ctxt->vstateNr - 1);
614 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
615 xmlValidDebugState(&ctxt->vstateTab[j]);
616 xmlGenericError(xmlGenericErrorContext, "\n");
617 }
618
619 /*****
620 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
621 *****/
622
623 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
624 #define DEBUG_VALID_MSG(m) \
625 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
626
627 #else
628 #define DEBUG_VALID_STATE(n,c)
629 #define DEBUG_VALID_MSG(m)
630 #endif
631
632 /* TODO: use hash table for accesses to elem and attribute definitions */
633
634
635 #define CHECK_DTD \
636 if (doc == NULL) return(0); \
637 else if ((doc->intSubset == NULL) && \
638 (doc->extSubset == NULL)) return(0)
639
640 #ifdef LIBXML_REGEXP_ENABLED
641
642 /************************************************************************
643 * *
644 * Content model validation based on the regexps *
645 * *
646 ************************************************************************/
647
648 /**
649 * xmlValidBuildAContentModel:
650 * @content: the content model
651 * @ctxt: the schema parser context
652 * @name: the element name whose content is being built
653 *
654 * Generate the automata sequence needed for that type
655 *
656 * Returns 1 if successful or 0 in case of error.
657 */
658 static int
659 xmlValidBuildAContentModel(xmlElementContentPtr content,
660 xmlValidCtxtPtr ctxt,
661 const xmlChar *name) {
662 if (content == NULL) {
663 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
664 "Found NULL content in content model of %s\n",
665 name, NULL, NULL);
666 return(0);
667 }
668 switch (content->type) {
669 case XML_ELEMENT_CONTENT_PCDATA:
670 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
671 "Found PCDATA in content model of %s\n",
672 name, NULL, NULL);
673 return(0);
674 break;
675 case XML_ELEMENT_CONTENT_ELEMENT: {
676 xmlAutomataStatePtr oldstate = ctxt->state;
677 xmlChar fn[50];
678 xmlChar *fullname;
679
680 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
681 if (fullname == NULL) {
682 xmlVErrMemory(ctxt, "Building content model");
683 return(0);
684 }
685
686 switch (content->ocur) {
687 case XML_ELEMENT_CONTENT_ONCE:
688 ctxt->state = xmlAutomataNewTransition(ctxt->am,
689 ctxt->state, NULL, fullname, NULL);
690 break;
691 case XML_ELEMENT_CONTENT_OPT:
692 ctxt->state = xmlAutomataNewTransition(ctxt->am,
693 ctxt->state, NULL, fullname, NULL);
694 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
695 break;
696 case XML_ELEMENT_CONTENT_PLUS:
697 ctxt->state = xmlAutomataNewTransition(ctxt->am,
698 ctxt->state, NULL, fullname, NULL);
699 xmlAutomataNewTransition(ctxt->am, ctxt->state,
700 ctxt->state, fullname, NULL);
701 break;
702 case XML_ELEMENT_CONTENT_MULT:
703 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
704 ctxt->state, NULL);
705 xmlAutomataNewTransition(ctxt->am,
706 ctxt->state, ctxt->state, fullname, NULL);
707 break;
708 }
709 if ((fullname != fn) && (fullname != content->name))
710 xmlFree(fullname);
711 break;
712 }
713 case XML_ELEMENT_CONTENT_SEQ: {
714 xmlAutomataStatePtr oldstate, oldend;
715 xmlElementContentOccur ocur;
716
717 /*
718 * Simply iterate over the content
719 */
720 oldstate = ctxt->state;
721 ocur = content->ocur;
722 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
723 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
724 oldstate = ctxt->state;
725 }
726 do {
727 xmlValidBuildAContentModel(content->c1, ctxt, name);
728 content = content->c2;
729 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
730 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
731 xmlValidBuildAContentModel(content, ctxt, name);
732 oldend = ctxt->state;
733 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
734 switch (ocur) {
735 case XML_ELEMENT_CONTENT_ONCE:
736 break;
737 case XML_ELEMENT_CONTENT_OPT:
738 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
739 break;
740 case XML_ELEMENT_CONTENT_MULT:
741 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
742 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
743 break;
744 case XML_ELEMENT_CONTENT_PLUS:
745 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
746 break;
747 }
748 break;
749 }
750 case XML_ELEMENT_CONTENT_OR: {
751 xmlAutomataStatePtr oldstate, oldend;
752 xmlElementContentOccur ocur;
753
754 ocur = content->ocur;
755 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
756 (ocur == XML_ELEMENT_CONTENT_MULT)) {
757 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
758 ctxt->state, NULL);
759 }
760 oldstate = ctxt->state;
761 oldend = xmlAutomataNewState(ctxt->am);
762
763 /*
764 * iterate over the subtypes and remerge the end with an
765 * epsilon transition
766 */
767 do {
768 ctxt->state = oldstate;
769 xmlValidBuildAContentModel(content->c1, ctxt, name);
770 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
771 content = content->c2;
772 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
773 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
774 ctxt->state = oldstate;
775 xmlValidBuildAContentModel(content, ctxt, name);
776 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
777 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
778 switch (ocur) {
779 case XML_ELEMENT_CONTENT_ONCE:
780 break;
781 case XML_ELEMENT_CONTENT_OPT:
782 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
783 break;
784 case XML_ELEMENT_CONTENT_MULT:
785 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
786 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
787 break;
788 case XML_ELEMENT_CONTENT_PLUS:
789 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
790 break;
791 }
792 break;
793 }
794 default:
795 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
796 "ContentModel broken for element %s\n",
797 (const char *) name);
798 return(0);
799 }
800 return(1);
801 }
802 /**
803 * xmlValidBuildContentModel:
804 * @ctxt: a validation context
805 * @elem: an element declaration node
806 *
807 * (Re)Build the automata associated to the content model of this
808 * element
809 *
810 * Returns 1 in case of success, 0 in case of error
811 */
812 int
813 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
814
815 if ((ctxt == NULL) || (elem == NULL))
816 return(0);
817 if (elem->type != XML_ELEMENT_DECL)
818 return(0);
819 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
820 return(1);
821 /* TODO: should we rebuild in this case ? */
822 if (elem->contModel != NULL) {
823 if (!xmlRegexpIsDeterminist(elem->contModel)) {
824 ctxt->valid = 0;
825 return(0);
826 }
827 return(1);
828 }
829
830 ctxt->am = xmlNewAutomata();
831 if (ctxt->am == NULL) {
832 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
833 XML_ERR_INTERNAL_ERROR,
834 "Cannot create automata for element %s\n",
835 elem->name, NULL, NULL);
836 return(0);
837 }
838 ctxt->state = xmlAutomataGetInitState(ctxt->am);
839 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
840 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
841 elem->contModel = xmlAutomataCompile(ctxt->am);
842 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
843 char expr[5000];
844 expr[0] = 0;
845 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
846 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
847 XML_DTD_CONTENT_NOT_DETERMINIST,
848 "Content model of %s is not determinist: %s\n",
849 elem->name, BAD_CAST expr, NULL);
850 #ifdef DEBUG_REGEXP_ALGO
851 xmlRegexpPrint(stderr, elem->contModel);
852 #endif
853 ctxt->valid = 0;
854 ctxt->state = NULL;
855 xmlFreeAutomata(ctxt->am);
856 ctxt->am = NULL;
857 return(0);
858 }
859 ctxt->state = NULL;
860 xmlFreeAutomata(ctxt->am);
861 ctxt->am = NULL;
862 return(1);
863 }
864
865 #endif /* LIBXML_REGEXP_ENABLED */
866
867 /****************************************************************
868 * *
869 * Util functions for data allocation/deallocation *
870 * *
871 ****************************************************************/
872
873 /**
874 * xmlNewValidCtxt:
875 *
876 * Allocate a validation context structure.
877 *
878 * Returns NULL if not, otherwise the new validation context structure
879 */
880 xmlValidCtxtPtr xmlNewValidCtxt(void) {
881 xmlValidCtxtPtr ret;
882
883 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
884 xmlVErrMemory(NULL, "malloc failed");
885 return (NULL);
886 }
887
888 (void) memset(ret, 0, sizeof (xmlValidCtxt));
889
890 return (ret);
891 }
892
893 /**
894 * xmlFreeValidCtxt:
895 * @cur: the validation context to free
896 *
897 * Free a validation context structure.
898 */
899 void
900 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
901 if (cur->vstateTab != NULL)
902 xmlFree(cur->vstateTab);
903 if (cur->nodeTab != NULL)
904 xmlFree(cur->nodeTab);
905 xmlFree(cur);
906 }
907
908 #endif /* LIBXML_VALID_ENABLED */
909
910 /**
911 * xmlNewDocElementContent:
912 * @doc: the document
913 * @name: the subelement name or NULL
914 * @type: the type of element content decl
915 *
916 * Allocate an element content structure for the document.
917 *
918 * Returns NULL if not, otherwise the new element content structure
919 */
920 xmlElementContentPtr
921 xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
922 xmlElementContentType type) {
923 xmlElementContentPtr ret;
924 xmlDictPtr dict = NULL;
925
926 if (doc != NULL)
927 dict = doc->dict;
928
929 switch(type) {
930 case XML_ELEMENT_CONTENT_ELEMENT:
931 if (name == NULL) {
932 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
933 "xmlNewElementContent : name == NULL !\n",
934 NULL);
935 }
936 break;
937 case XML_ELEMENT_CONTENT_PCDATA:
938 case XML_ELEMENT_CONTENT_SEQ:
939 case XML_ELEMENT_CONTENT_OR:
940 if (name != NULL) {
941 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
942 "xmlNewElementContent : name != NULL !\n",
943 NULL);
944 }
945 break;
946 default:
947 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
948 "Internal: ELEMENT content corrupted invalid type\n",
949 NULL);
950 return(NULL);
951 }
952 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
953 if (ret == NULL) {
954 xmlVErrMemory(NULL, "malloc failed");
955 return(NULL);
956 }
957 memset(ret, 0, sizeof(xmlElementContent));
958 ret->type = type;
959 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
960 if (name != NULL) {
961 int l;
962 const xmlChar *tmp;
963
964 tmp = xmlSplitQName3(name, &l);
965 if (tmp == NULL) {
966 if (dict == NULL)
967 ret->name = xmlStrdup(name);
968 else
969 ret->name = xmlDictLookup(dict, name, -1);
970 } else {
971 if (dict == NULL) {
972 ret->prefix = xmlStrndup(name, l);
973 ret->name = xmlStrdup(tmp);
974 } else {
975 ret->prefix = xmlDictLookup(dict, name, l);
976 ret->name = xmlDictLookup(dict, tmp, -1);
977 }
978 }
979 }
980 return(ret);
981 }
982
983 /**
984 * xmlNewElementContent:
985 * @name: the subelement name or NULL
986 * @type: the type of element content decl
987 *
988 * Allocate an element content structure.
989 * Deprecated in favor of xmlNewDocElementContent
990 *
991 * Returns NULL if not, otherwise the new element content structure
992 */
993 xmlElementContentPtr
994 xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
995 return(xmlNewDocElementContent(NULL, name, type));
996 }
997
998 /**
999 * xmlCopyDocElementContent:
1000 * @doc: the document owning the element declaration
1001 * @cur: An element content pointer.
1002 *
1003 * Build a copy of an element content description.
1004 *
1005 * Returns the new xmlElementContentPtr or NULL in case of error.
1006 */
1007 xmlElementContentPtr
1008 xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1009 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1010 xmlDictPtr dict = NULL;
1011
1012 if (cur == NULL) return(NULL);
1013
1014 if (doc != NULL)
1015 dict = doc->dict;
1016
1017 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1018 if (ret == NULL) {
1019 xmlVErrMemory(NULL, "malloc failed");
1020 return(NULL);
1021 }
1022 memset(ret, 0, sizeof(xmlElementContent));
1023 ret->type = cur->type;
1024 ret->ocur = cur->ocur;
1025 if (cur->name != NULL) {
1026 if (dict)
1027 ret->name = xmlDictLookup(dict, cur->name, -1);
1028 else
1029 ret->name = xmlStrdup(cur->name);
1030 }
1031
1032 if (cur->prefix != NULL) {
1033 if (dict)
1034 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1035 else
1036 ret->prefix = xmlStrdup(cur->prefix);
1037 }
1038 if (cur->c1 != NULL)
1039 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1040 if (ret->c1 != NULL)
1041 ret->c1->parent = ret;
1042 if (cur->c2 != NULL) {
1043 prev = ret;
1044 cur = cur->c2;
1045 while (cur != NULL) {
1046 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1047 if (tmp == NULL) {
1048 xmlVErrMemory(NULL, "malloc failed");
1049 return(ret);
1050 }
1051 memset(tmp, 0, sizeof(xmlElementContent));
1052 tmp->type = cur->type;
1053 tmp->ocur = cur->ocur;
1054 prev->c2 = tmp;
1055 if (cur->name != NULL) {
1056 if (dict)
1057 tmp->name = xmlDictLookup(dict, cur->name, -1);
1058 else
1059 tmp->name = xmlStrdup(cur->name);
1060 }
1061
1062 if (cur->prefix != NULL) {
1063 if (dict)
1064 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1065 else
1066 tmp->prefix = xmlStrdup(cur->prefix);
1067 }
1068 if (cur->c1 != NULL)
1069 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1070 if (tmp->c1 != NULL)
1071 tmp->c1->parent = ret;
1072 prev = tmp;
1073 cur = cur->c2;
1074 }
1075 }
1076 return(ret);
1077 }
1078
1079 /**
1080 * xmlCopyElementContent:
1081 * @cur: An element content pointer.
1082 *
1083 * Build a copy of an element content description.
1084 * Deprecated, use xmlCopyDocElementContent instead
1085 *
1086 * Returns the new xmlElementContentPtr or NULL in case of error.
1087 */
1088 xmlElementContentPtr
1089 xmlCopyElementContent(xmlElementContentPtr cur) {
1090 return(xmlCopyDocElementContent(NULL, cur));
1091 }
1092
1093 /**
1094 * xmlFreeDocElementContent:
1095 * @doc: the document owning the element declaration
1096 * @cur: the element content tree to free
1097 *
1098 * Free an element content structure. The whole subtree is removed.
1099 */
1100 void
1101 xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1102 xmlElementContentPtr next;
1103 xmlDictPtr dict = NULL;
1104
1105 if (doc != NULL)
1106 dict = doc->dict;
1107
1108 while (cur != NULL) {
1109 next = cur->c2;
1110 switch (cur->type) {
1111 case XML_ELEMENT_CONTENT_PCDATA:
1112 case XML_ELEMENT_CONTENT_ELEMENT:
1113 case XML_ELEMENT_CONTENT_SEQ:
1114 case XML_ELEMENT_CONTENT_OR:
1115 break;
1116 default:
1117 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1118 "Internal: ELEMENT content corrupted invalid type\n",
1119 NULL);
1120 return;
1121 }
1122 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1123 if (dict) {
1124 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1125 xmlFree((xmlChar *) cur->name);
1126 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1127 xmlFree((xmlChar *) cur->prefix);
1128 } else {
1129 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1130 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1131 }
1132 xmlFree(cur);
1133 cur = next;
1134 }
1135 }
1136
1137 /**
1138 * xmlFreeElementContent:
1139 * @cur: the element content tree to free
1140 *
1141 * Free an element content structure. The whole subtree is removed.
1142 * Deprecated, use xmlFreeDocElementContent instead
1143 */
1144 void
1145 xmlFreeElementContent(xmlElementContentPtr cur) {
1146 xmlFreeDocElementContent(NULL, cur);
1147 }
1148
1149 #ifdef LIBXML_OUTPUT_ENABLED
1150 /**
1151 * xmlDumpElementContent:
1152 * @buf: An XML buffer
1153 * @content: An element table
1154 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1155 *
1156 * This will dump the content of the element table as an XML DTD definition
1157 */
1158 static void
1159 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1160 if (content == NULL) return;
1161
1162 if (glob) xmlBufferWriteChar(buf, "(");
1163 switch (content->type) {
1164 case XML_ELEMENT_CONTENT_PCDATA:
1165 xmlBufferWriteChar(buf, "#PCDATA");
1166 break;
1167 case XML_ELEMENT_CONTENT_ELEMENT:
1168 if (content->prefix != NULL) {
1169 xmlBufferWriteCHAR(buf, content->prefix);
1170 xmlBufferWriteChar(buf, ":");
1171 }
1172 xmlBufferWriteCHAR(buf, content->name);
1173 break;
1174 case XML_ELEMENT_CONTENT_SEQ:
1175 if ((content->c1 != NULL) &&
1176 ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1177 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
1178 xmlDumpElementContent(buf, content->c1, 1);
1179 else
1180 xmlDumpElementContent(buf, content->c1, 0);
1181 xmlBufferWriteChar(buf, " , ");
1182 if ((content->c2 != NULL) &&
1183 ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1184 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1185 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
1186 xmlDumpElementContent(buf, content->c2, 1);
1187 else
1188 xmlDumpElementContent(buf, content->c2, 0);
1189 break;
1190 case XML_ELEMENT_CONTENT_OR:
1191 if ((content->c1 != NULL) &&
1192 ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1193 (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
1194 xmlDumpElementContent(buf, content->c1, 1);
1195 else
1196 xmlDumpElementContent(buf, content->c1, 0);
1197 xmlBufferWriteChar(buf, " | ");
1198 if ((content->c2 != NULL) &&
1199 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1200 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1201 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
1202 xmlDumpElementContent(buf, content->c2, 1);
1203 else
1204 xmlDumpElementContent(buf, content->c2, 0);
1205 break;
1206 default:
1207 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1208 "Internal: ELEMENT content corrupted invalid type\n",
1209 NULL);
1210 }
1211 if (glob)
1212 xmlBufferWriteChar(buf, ")");
1213 switch (content->ocur) {
1214 case XML_ELEMENT_CONTENT_ONCE:
1215 break;
1216 case XML_ELEMENT_CONTENT_OPT:
1217 xmlBufferWriteChar(buf, "?");
1218 break;
1219 case XML_ELEMENT_CONTENT_MULT:
1220 xmlBufferWriteChar(buf, "*");
1221 break;
1222 case XML_ELEMENT_CONTENT_PLUS:
1223 xmlBufferWriteChar(buf, "+");
1224 break;
1225 }
1226 }
1227
1228 /**
1229 * xmlSprintfElementContent:
1230 * @buf: an output buffer
1231 * @content: An element table
1232 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1233 *
1234 * Deprecated, unsafe, use xmlSnprintfElementContent
1235 */
1236 void
1237 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1238 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1239 int englob ATTRIBUTE_UNUSED) {
1240 }
1241 #endif /* LIBXML_OUTPUT_ENABLED */
1242
1243 /**
1244 * xmlSnprintfElementContent:
1245 * @buf: an output buffer
1246 * @size: the buffer size
1247 * @content: An element table
1248 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1249 *
1250 * This will dump the content of the element content definition
1251 * Intended just for the debug routine
1252 */
1253 void
1254 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1255 int len;
1256
1257 if (content == NULL) return;
1258 len = strlen(buf);
1259 if (size - len < 50) {
1260 if ((size - len > 4) && (buf[len - 1] != '.'))
1261 strcat(buf, " ...");
1262 return;
1263 }
1264 if (englob) strcat(buf, "(");
1265 switch (content->type) {
1266 case XML_ELEMENT_CONTENT_PCDATA:
1267 strcat(buf, "#PCDATA");
1268 break;
1269 case XML_ELEMENT_CONTENT_ELEMENT: {
1270 int qnameLen = xmlStrlen(content->name);
1271
1272 if (content->prefix != NULL)
1273 qnameLen += xmlStrlen(content->prefix) + 1;
1274 if (size - len < qnameLen + 10) {
1275 strcat(buf, " ...");
1276 return;
1277 }
1278 if (content->prefix != NULL) {
1279 strcat(buf, (char *) content->prefix);
1280 strcat(buf, ":");
1281 }
1282 if (content->name != NULL)
1283 strcat(buf, (char *) content->name);
1284 break;
1285 }
1286 case XML_ELEMENT_CONTENT_SEQ:
1287 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1288 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1289 xmlSnprintfElementContent(buf, size, content->c1, 1);
1290 else
1291 xmlSnprintfElementContent(buf, size, content->c1, 0);
1292 len = strlen(buf);
1293 if (size - len < 50) {
1294 if ((size - len > 4) && (buf[len - 1] != '.'))
1295 strcat(buf, " ...");
1296 return;
1297 }
1298 strcat(buf, " , ");
1299 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1300 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1301 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1302 xmlSnprintfElementContent(buf, size, content->c2, 1);
1303 else
1304 xmlSnprintfElementContent(buf, size, content->c2, 0);
1305 break;
1306 case XML_ELEMENT_CONTENT_OR:
1307 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1308 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1309 xmlSnprintfElementContent(buf, size, content->c1, 1);
1310 else
1311 xmlSnprintfElementContent(buf, size, content->c1, 0);
1312 len = strlen(buf);
1313 if (size - len < 50) {
1314 if ((size - len > 4) && (buf[len - 1] != '.'))
1315 strcat(buf, " ...");
1316 return;
1317 }
1318 strcat(buf, " | ");
1319 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1320 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1321 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1322 xmlSnprintfElementContent(buf, size, content->c2, 1);
1323 else
1324 xmlSnprintfElementContent(buf, size, content->c2, 0);
1325 break;
1326 }
1327 if (size - strlen(buf) <= 2) return;
1328 if (englob)
1329 strcat(buf, ")");
1330 switch (content->ocur) {
1331 case XML_ELEMENT_CONTENT_ONCE:
1332 break;
1333 case XML_ELEMENT_CONTENT_OPT:
1334 strcat(buf, "?");
1335 break;
1336 case XML_ELEMENT_CONTENT_MULT:
1337 strcat(buf, "*");
1338 break;
1339 case XML_ELEMENT_CONTENT_PLUS:
1340 strcat(buf, "+");
1341 break;
1342 }
1343 }
1344
1345 /****************************************************************
1346 * *
1347 * Registration of DTD declarations *
1348 * *
1349 ****************************************************************/
1350
1351 /**
1352 * xmlFreeElement:
1353 * @elem: An element
1354 *
1355 * Deallocate the memory used by an element definition
1356 */
1357 static void
1358 xmlFreeElement(xmlElementPtr elem) {
1359 if (elem == NULL) return;
1360 xmlUnlinkNode((xmlNodePtr) elem);
1361 xmlFreeDocElementContent(elem->doc, elem->content);
1362 if (elem->name != NULL)
1363 xmlFree((xmlChar *) elem->name);
1364 if (elem->prefix != NULL)
1365 xmlFree((xmlChar *) elem->prefix);
1366 #ifdef LIBXML_REGEXP_ENABLED
1367 if (elem->contModel != NULL)
1368 xmlRegFreeRegexp(elem->contModel);
1369 #endif
1370 xmlFree(elem);
1371 }
1372
1373
1374 /**
1375 * xmlAddElementDecl:
1376 * @ctxt: the validation context
1377 * @dtd: pointer to the DTD
1378 * @name: the entity name
1379 * @type: the element type
1380 * @content: the element content tree or NULL
1381 *
1382 * Register a new element declaration
1383 *
1384 * Returns NULL if not, otherwise the entity
1385 */
1386 xmlElementPtr
1387 xmlAddElementDecl(xmlValidCtxtPtr ctxt,
1388 xmlDtdPtr dtd, const xmlChar *name,
1389 xmlElementTypeVal type,
1390 xmlElementContentPtr content) {
1391 xmlElementPtr ret;
1392 xmlElementTablePtr table;
1393 xmlAttributePtr oldAttributes = NULL;
1394 xmlChar *ns, *uqname;
1395
1396 if (dtd == NULL) {
1397 return(NULL);
1398 }
1399 if (name == NULL) {
1400 return(NULL);
1401 }
1402
1403 switch (type) {
1404 case XML_ELEMENT_TYPE_EMPTY:
1405 if (content != NULL) {
1406 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1407 "xmlAddElementDecl: content != NULL for EMPTY\n",
1408 NULL);
1409 return(NULL);
1410 }
1411 break;
1412 case XML_ELEMENT_TYPE_ANY:
1413 if (content != NULL) {
1414 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1415 "xmlAddElementDecl: content != NULL for ANY\n",
1416 NULL);
1417 return(NULL);
1418 }
1419 break;
1420 case XML_ELEMENT_TYPE_MIXED:
1421 if (content == NULL) {
1422 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1423 "xmlAddElementDecl: content == NULL for MIXED\n",
1424 NULL);
1425 return(NULL);
1426 }
1427 break;
1428 case XML_ELEMENT_TYPE_ELEMENT:
1429 if (content == NULL) {
1430 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1431 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1432 NULL);
1433 return(NULL);
1434 }
1435 break;
1436 default:
1437 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1438 "Internal: ELEMENT decl corrupted invalid type\n",
1439 NULL);
1440 return(NULL);
1441 }
1442
1443 /*
1444 * check if name is a QName
1445 */
1446 uqname = xmlSplitQName2(name, &ns);
1447 if (uqname != NULL)
1448 name = uqname;
1449
1450 /*
1451 * Create the Element table if needed.
1452 */
1453 table = (xmlElementTablePtr) dtd->elements;
1454 if (table == NULL) {
1455 xmlDictPtr dict = NULL;
1456
1457 if (dtd->doc != NULL)
1458 dict = dtd->doc->dict;
1459 table = xmlHashCreateDict(0, dict);
1460 dtd->elements = (void *) table;
1461 }
1462 if (table == NULL) {
1463 xmlVErrMemory(ctxt,
1464 "xmlAddElementDecl: Table creation failed!\n");
1465 if (uqname != NULL)
1466 xmlFree(uqname);
1467 if (ns != NULL)
1468 xmlFree(ns);
1469 return(NULL);
1470 }
1471
1472 /*
1473 * lookup old attributes inserted on an undefined element in the
1474 * internal subset.
1475 */
1476 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1477 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1478 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1479 oldAttributes = ret->attributes;
1480 ret->attributes = NULL;
1481 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1482 xmlFreeElement(ret);
1483 }
1484 }
1485
1486 /*
1487 * The element may already be present if one of its attribute
1488 * was registered first
1489 */
1490 ret = xmlHashLookup2(table, name, ns);
1491 if (ret != NULL) {
1492 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1493 #ifdef LIBXML_VALID_ENABLED
1494 /*
1495 * The element is already defined in this DTD.
1496 */
1497 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1498 "Redefinition of element %s\n",
1499 name, NULL, NULL);
1500 #endif /* LIBXML_VALID_ENABLED */
1501 if (uqname != NULL)
1502 xmlFree(uqname);
1503 if (ns != NULL)
1504 xmlFree(ns);
1505 return(NULL);
1506 }
1507 if (ns != NULL) {
1508 xmlFree(ns);
1509 ns = NULL;
1510 }
1511 } else {
1512 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1513 if (ret == NULL) {
1514 xmlVErrMemory(ctxt, "malloc failed");
1515 if (uqname != NULL)
1516 xmlFree(uqname);
1517 if (ns != NULL)
1518 xmlFree(ns);
1519 return(NULL);
1520 }
1521 memset(ret, 0, sizeof(xmlElement));
1522 ret->type = XML_ELEMENT_DECL;
1523
1524 /*
1525 * fill the structure.
1526 */
1527 ret->name = xmlStrdup(name);
1528 if (ret->name == NULL) {
1529 xmlVErrMemory(ctxt, "malloc failed");
1530 if (uqname != NULL)
1531 xmlFree(uqname);
1532 if (ns != NULL)
1533 xmlFree(ns);
1534 xmlFree(ret);
1535 return(NULL);
1536 }
1537 ret->prefix = ns;
1538
1539 /*
1540 * Validity Check:
1541 * Insertion must not fail
1542 */
1543 if (xmlHashAddEntry2(table, name, ns, ret)) {
1544 #ifdef LIBXML_VALID_ENABLED
1545 /*
1546 * The element is already defined in this DTD.
1547 */
1548 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1549 "Redefinition of element %s\n",
1550 name, NULL, NULL);
1551 #endif /* LIBXML_VALID_ENABLED */
1552 xmlFreeElement(ret);
1553 if (uqname != NULL)
1554 xmlFree(uqname);
1555 return(NULL);
1556 }
1557 /*
1558 * For new element, may have attributes from earlier
1559 * definition in internal subset
1560 */
1561 ret->attributes = oldAttributes;
1562 }
1563
1564 /*
1565 * Finish to fill the structure.
1566 */
1567 ret->etype = type;
1568 /*
1569 * Avoid a stupid copy when called by the parser
1570 * and flag it by setting a special parent value
1571 * so the parser doesn't unallocate it.
1572 */
1573 if ((ctxt != NULL) &&
1574 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1575 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
1576 ret->content = content;
1577 if (content != NULL)
1578 content->parent = (xmlElementContentPtr) 1;
1579 } else {
1580 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1581 }
1582
1583 /*
1584 * Link it to the DTD
1585 */
1586 ret->parent = dtd;
1587 ret->doc = dtd->doc;
1588 if (dtd->last == NULL) {
1589 dtd->children = dtd->last = (xmlNodePtr) ret;
1590 } else {
1591 dtd->last->next = (xmlNodePtr) ret;
1592 ret->prev = dtd->last;
1593 dtd->last = (xmlNodePtr) ret;
1594 }
1595 if (uqname != NULL)
1596 xmlFree(uqname);
1597 return(ret);
1598 }
1599
1600 /**
1601 * xmlFreeElementTable:
1602 * @table: An element table
1603 *
1604 * Deallocate the memory used by an element hash table.
1605 */
1606 void
1607 xmlFreeElementTable(xmlElementTablePtr table) {
1608 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1609 }
1610
1611 #ifdef LIBXML_TREE_ENABLED
1612 /**
1613 * xmlCopyElement:
1614 * @elem: An element
1615 *
1616 * Build a copy of an element.
1617 *
1618 * Returns the new xmlElementPtr or NULL in case of error.
1619 */
1620 static xmlElementPtr
1621 xmlCopyElement(xmlElementPtr elem) {
1622 xmlElementPtr cur;
1623
1624 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1625 if (cur == NULL) {
1626 xmlVErrMemory(NULL, "malloc failed");
1627 return(NULL);
1628 }
1629 memset(cur, 0, sizeof(xmlElement));
1630 cur->type = XML_ELEMENT_DECL;
1631 cur->etype = elem->etype;
1632 if (elem->name != NULL)
1633 cur->name = xmlStrdup(elem->name);
1634 else
1635 cur->name = NULL;
1636 if (elem->prefix != NULL)
1637 cur->prefix = xmlStrdup(elem->prefix);
1638 else
1639 cur->prefix = NULL;
1640 cur->content = xmlCopyElementContent(elem->content);
1641 /* TODO : rebuild the attribute list on the copy */
1642 cur->attributes = NULL;
1643 return(cur);
1644 }
1645
1646 /**
1647 * xmlCopyElementTable:
1648 * @table: An element table
1649 *
1650 * Build a copy of an element table.
1651 *
1652 * Returns the new xmlElementTablePtr or NULL in case of error.
1653 */
1654 xmlElementTablePtr
1655 xmlCopyElementTable(xmlElementTablePtr table) {
1656 return((xmlElementTablePtr) xmlHashCopy(table,
1657 (xmlHashCopier) xmlCopyElement));
1658 }
1659 #endif /* LIBXML_TREE_ENABLED */
1660
1661 #ifdef LIBXML_OUTPUT_ENABLED
1662 /**
1663 * xmlDumpElementDecl:
1664 * @buf: the XML buffer output
1665 * @elem: An element table
1666 *
1667 * This will dump the content of the element declaration as an XML
1668 * DTD definition
1669 */
1670 void
1671 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1672 if ((buf == NULL) || (elem == NULL))
1673 return;
1674 switch (elem->etype) {
1675 case XML_ELEMENT_TYPE_EMPTY:
1676 xmlBufferWriteChar(buf, "<!ELEMENT ");
1677 if (elem->prefix != NULL) {
1678 xmlBufferWriteCHAR(buf, elem->prefix);
1679 xmlBufferWriteChar(buf, ":");
1680 }
1681 xmlBufferWriteCHAR(buf, elem->name);
1682 xmlBufferWriteChar(buf, " EMPTY>\n");
1683 break;
1684 case XML_ELEMENT_TYPE_ANY:
1685 xmlBufferWriteChar(buf, "<!ELEMENT ");
1686 if (elem->prefix != NULL) {
1687 xmlBufferWriteCHAR(buf, elem->prefix);
1688 xmlBufferWriteChar(buf, ":");
1689 }
1690 xmlBufferWriteCHAR(buf, elem->name);
1691 xmlBufferWriteChar(buf, " ANY>\n");
1692 break;
1693 case XML_ELEMENT_TYPE_MIXED:
1694 xmlBufferWriteChar(buf, "<!ELEMENT ");
1695 if (elem->prefix != NULL) {
1696 xmlBufferWriteCHAR(buf, elem->prefix);
1697 xmlBufferWriteChar(buf, ":");
1698 }
1699 xmlBufferWriteCHAR(buf, elem->name);
1700 xmlBufferWriteChar(buf, " ");
1701 xmlDumpElementContent(buf, elem->content, 1);
1702 xmlBufferWriteChar(buf, ">\n");
1703 break;
1704 case XML_ELEMENT_TYPE_ELEMENT:
1705 xmlBufferWriteChar(buf, "<!ELEMENT ");
1706 if (elem->prefix != NULL) {
1707 xmlBufferWriteCHAR(buf, elem->prefix);
1708 xmlBufferWriteChar(buf, ":");
1709 }
1710 xmlBufferWriteCHAR(buf, elem->name);
1711 xmlBufferWriteChar(buf, " ");
1712 xmlDumpElementContent(buf, elem->content, 1);
1713 xmlBufferWriteChar(buf, ">\n");
1714 break;
1715 default:
1716 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1717 "Internal: ELEMENT struct corrupted invalid type\n",
1718 NULL);
1719 }
1720 }
1721
1722 /**
1723 * xmlDumpElementDeclScan:
1724 * @elem: An element table
1725 * @buf: the XML buffer output
1726 *
1727 * This routine is used by the hash scan function. It just reverses
1728 * the arguments.
1729 */
1730 static void
1731 xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1732 xmlDumpElementDecl(buf, elem);
1733 }
1734
1735 /**
1736 * xmlDumpElementTable:
1737 * @buf: the XML buffer output
1738 * @table: An element table
1739 *
1740 * This will dump the content of the element table as an XML DTD definition
1741 */
1742 void
1743 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1744 if ((buf == NULL) || (table == NULL))
1745 return;
1746 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
1747 }
1748 #endif /* LIBXML_OUTPUT_ENABLED */
1749
1750 /**
1751 * xmlCreateEnumeration:
1752 * @name: the enumeration name or NULL
1753 *
1754 * create and initialize an enumeration attribute node.
1755 *
1756 * Returns the xmlEnumerationPtr just created or NULL in case
1757 * of error.
1758 */
1759 xmlEnumerationPtr
1760 xmlCreateEnumeration(const xmlChar *name) {
1761 xmlEnumerationPtr ret;
1762
1763 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1764 if (ret == NULL) {
1765 xmlVErrMemory(NULL, "malloc failed");
1766 return(NULL);
1767 }
1768 memset(ret, 0, sizeof(xmlEnumeration));
1769
1770 if (name != NULL)
1771 ret->name = xmlStrdup(name);
1772 return(ret);
1773 }
1774
1775 /**
1776 * xmlFreeEnumeration:
1777 * @cur: the tree to free.
1778 *
1779 * free an enumeration attribute node (recursive).
1780 */
1781 void
1782 xmlFreeEnumeration(xmlEnumerationPtr cur) {
1783 if (cur == NULL) return;
1784
1785 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1786
1787 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1788 xmlFree(cur);
1789 }
1790
1791 #ifdef LIBXML_TREE_ENABLED
1792 /**
1793 * xmlCopyEnumeration:
1794 * @cur: the tree to copy.
1795 *
1796 * Copy an enumeration attribute node (recursive).
1797 *
1798 * Returns the xmlEnumerationPtr just created or NULL in case
1799 * of error.
1800 */
1801 xmlEnumerationPtr
1802 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1803 xmlEnumerationPtr ret;
1804
1805 if (cur == NULL) return(NULL);
1806 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1807 if (ret == NULL) return(NULL);
1808
1809 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1810 else ret->next = NULL;
1811
1812 return(ret);
1813 }
1814 #endif /* LIBXML_TREE_ENABLED */
1815
1816 #ifdef LIBXML_OUTPUT_ENABLED
1817 /**
1818 * xmlDumpEnumeration:
1819 * @buf: the XML buffer output
1820 * @enum: An enumeration
1821 *
1822 * This will dump the content of the enumeration
1823 */
1824 static void
1825 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1826 if ((buf == NULL) || (cur == NULL))
1827 return;
1828
1829 xmlBufferWriteCHAR(buf, cur->name);
1830 if (cur->next == NULL)
1831 xmlBufferWriteChar(buf, ")");
1832 else {
1833 xmlBufferWriteChar(buf, " | ");
1834 xmlDumpEnumeration(buf, cur->next);
1835 }
1836 }
1837 #endif /* LIBXML_OUTPUT_ENABLED */
1838
1839 #ifdef LIBXML_VALID_ENABLED
1840 /**
1841 * xmlScanIDAttributeDecl:
1842 * @ctxt: the validation context
1843 * @elem: the element name
1844 * @err: whether to raise errors here
1845 *
1846 * Verify that the element don't have too many ID attributes
1847 * declared.
1848 *
1849 * Returns the number of ID attributes found.
1850 */
1851 static int
1852 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1853 xmlAttributePtr cur;
1854 int ret = 0;
1855
1856 if (elem == NULL) return(0);
1857 cur = elem->attributes;
1858 while (cur != NULL) {
1859 if (cur->atype == XML_ATTRIBUTE_ID) {
1860 ret ++;
1861 if ((ret > 1) && (err))
1862 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1863 "Element %s has too many ID attributes defined : %s\n",
1864 elem->name, cur->name, NULL);
1865 }
1866 cur = cur->nexth;
1867 }
1868 return(ret);
1869 }
1870 #endif /* LIBXML_VALID_ENABLED */
1871
1872 /**
1873 * xmlFreeAttribute:
1874 * @elem: An attribute
1875 *
1876 * Deallocate the memory used by an attribute definition
1877 */
1878 static void
1879 xmlFreeAttribute(xmlAttributePtr attr) {
1880 xmlDictPtr dict;
1881
1882 if (attr == NULL) return;
1883 if (attr->doc != NULL)
1884 dict = attr->doc->dict;
1885 else
1886 dict = NULL;
1887 xmlUnlinkNode((xmlNodePtr) attr);
1888 if (attr->tree != NULL)
1889 xmlFreeEnumeration(attr->tree);
1890 if (dict) {
1891 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1892 xmlFree((xmlChar *) attr->elem);
1893 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1894 xmlFree((xmlChar *) attr->name);
1895 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1896 xmlFree((xmlChar *) attr->prefix);
1897 if ((attr->defaultValue != NULL) &&
1898 (!xmlDictOwns(dict, attr->defaultValue)))
1899 xmlFree((xmlChar *) attr->defaultValue);
1900 } else {
1901 if (attr->elem != NULL)
1902 xmlFree((xmlChar *) attr->elem);
1903 if (attr->name != NULL)
1904 xmlFree((xmlChar *) attr->name);
1905 if (attr->defaultValue != NULL)
1906 xmlFree((xmlChar *) attr->defaultValue);
1907 if (attr->prefix != NULL)
1908 xmlFree((xmlChar *) attr->prefix);
1909 }
1910 xmlFree(attr);
1911 }
1912
1913
1914 /**
1915 * xmlAddAttributeDecl:
1916 * @ctxt: the validation context
1917 * @dtd: pointer to the DTD
1918 * @elem: the element name
1919 * @name: the attribute name
1920 * @ns: the attribute namespace prefix
1921 * @type: the attribute type
1922 * @def: the attribute default type
1923 * @defaultValue: the attribute default value
1924 * @tree: if it's an enumeration, the associated list
1925 *
1926 * Register a new attribute declaration
1927 * Note that @tree becomes the ownership of the DTD
1928 *
1929 * Returns NULL if not new, otherwise the attribute decl
1930 */
1931 xmlAttributePtr
1932 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
1933 xmlDtdPtr dtd, const xmlChar *elem,
1934 const xmlChar *name, const xmlChar *ns,
1935 xmlAttributeType type, xmlAttributeDefault def,
1936 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1937 xmlAttributePtr ret;
1938 xmlAttributeTablePtr table;
1939 xmlElementPtr elemDef;
1940 xmlDictPtr dict = NULL;
1941
1942 if (dtd == NULL) {
1943 xmlFreeEnumeration(tree);
1944 return(NULL);
1945 }
1946 if (name == NULL) {
1947 xmlFreeEnumeration(tree);
1948 return(NULL);
1949 }
1950 if (elem == NULL) {
1951 xmlFreeEnumeration(tree);
1952 return(NULL);
1953 }
1954 if (dtd->doc != NULL)
1955 dict = dtd->doc->dict;
1956
1957 #ifdef LIBXML_VALID_ENABLED
1958 /*
1959 * Check the type and possibly the default value.
1960 */
1961 switch (type) {
1962 case XML_ATTRIBUTE_CDATA:
1963 break;
1964 case XML_ATTRIBUTE_ID:
1965 break;
1966 case XML_ATTRIBUTE_IDREF:
1967 break;
1968 case XML_ATTRIBUTE_IDREFS:
1969 break;
1970 case XML_ATTRIBUTE_ENTITY:
1971 break;
1972 case XML_ATTRIBUTE_ENTITIES:
1973 break;
1974 case XML_ATTRIBUTE_NMTOKEN:
1975 break;
1976 case XML_ATTRIBUTE_NMTOKENS:
1977 break;
1978 case XML_ATTRIBUTE_ENUMERATION:
1979 break;
1980 case XML_ATTRIBUTE_NOTATION:
1981 break;
1982 default:
1983 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1984 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1985 NULL);
1986 xmlFreeEnumeration(tree);
1987 return(NULL);
1988 }
1989 if ((defaultValue != NULL) &&
1990 (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
1991 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1992 "Attribute %s of %s: invalid default value\n",
1993 elem, name, defaultValue);
1994 defaultValue = NULL;
1995 if (ctxt != NULL)
1996 ctxt->valid = 0;
1997 }
1998 #endif /* LIBXML_VALID_ENABLED */
1999
2000 /*
2001 * Check first that an attribute defined in the external subset wasn't
2002 * already defined in the internal subset
2003 */
2004 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2005 (dtd->doc->intSubset != NULL) &&
2006 (dtd->doc->intSubset->attributes != NULL)) {
2007 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2008 if (ret != NULL) {
2009 xmlFreeEnumeration(tree);
2010 return(NULL);
2011 }
2012 }
2013
2014 /*
2015 * Create the Attribute table if needed.
2016 */
2017 table = (xmlAttributeTablePtr) dtd->attributes;
2018 if (table == NULL) {
2019 table = xmlHashCreateDict(0, dict);
2020 dtd->attributes = (void *) table;
2021 }
2022 if (table == NULL) {
2023 xmlVErrMemory(ctxt,
2024 "xmlAddAttributeDecl: Table creation failed!\n");
2025 xmlFreeEnumeration(tree);
2026 return(NULL);
2027 }
2028
2029
2030 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2031 if (ret == NULL) {
2032 xmlVErrMemory(ctxt, "malloc failed");
2033 xmlFreeEnumeration(tree);
2034 return(NULL);
2035 }
2036 memset(ret, 0, sizeof(xmlAttribute));
2037 ret->type = XML_ATTRIBUTE_DECL;
2038
2039 /*
2040 * fill the structure.
2041 */
2042 ret->atype = type;
2043 /*
2044 * doc must be set before possible error causes call
2045 * to xmlFreeAttribute (because it's used to check on
2046 * dict use)
2047 */
2048 ret->doc = dtd->doc;
2049 if (dict) {
2050 ret->name = xmlDictLookup(dict, name, -1);
2051 ret->prefix = xmlDictLookup(dict, ns, -1);
2052 ret->elem = xmlDictLookup(dict, elem, -1);
2053 } else {
2054 ret->name = xmlStrdup(name);
2055 ret->prefix = xmlStrdup(ns);
2056 ret->elem = xmlStrdup(elem);
2057 }
2058 ret->def = def;
2059 ret->tree = tree;
2060 if (defaultValue != NULL) {
2061 if (dict)
2062 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2063 else
2064 ret->defaultValue = xmlStrdup(defaultValue);
2065 }
2066
2067 /*
2068 * Validity Check:
2069 * Search the DTD for previous declarations of the ATTLIST
2070 */
2071 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2072 #ifdef LIBXML_VALID_ENABLED
2073 /*
2074 * The attribute is already defined in this DTD.
2075 */
2076 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2077 "Attribute %s of element %s: already defined\n",
2078 name, elem, NULL);
2079 #endif /* LIBXML_VALID_ENABLED */
2080 xmlFreeAttribute(ret);
2081 return(NULL);
2082 }
2083
2084 /*
2085 * Validity Check:
2086 * Multiple ID per element
2087 */
2088 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2089 if (elemDef != NULL) {
2090
2091 #ifdef LIBXML_VALID_ENABLED
2092 if ((type == XML_ATTRIBUTE_ID) &&
2093 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2094 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2095 "Element %s has too may ID attributes defined : %s\n",
2096 elem, name, NULL);
2097 if (ctxt != NULL)
2098 ctxt->valid = 0;
2099 }
2100 #endif /* LIBXML_VALID_ENABLED */
2101
2102 /*
2103 * Insert namespace default def first they need to be
2104 * processed first.
2105 */
2106 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2107 ((ret->prefix != NULL &&
2108 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2109 ret->nexth = elemDef->attributes;
2110 elemDef->attributes = ret;
2111 } else {
2112 xmlAttributePtr tmp = elemDef->attributes;
2113
2114 while ((tmp != NULL) &&
2115 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2116 ((ret->prefix != NULL &&
2117 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2118 if (tmp->nexth == NULL)
2119 break;
2120 tmp = tmp->nexth;
2121 }
2122 if (tmp != NULL) {
2123 ret->nexth = tmp->nexth;
2124 tmp->nexth = ret;
2125 } else {
2126 ret->nexth = elemDef->attributes;
2127 elemDef->attributes = ret;
2128 }
2129 }
2130 }
2131
2132 /*
2133 * Link it to the DTD
2134 */
2135 ret->parent = dtd;
2136 if (dtd->last == NULL) {
2137 dtd->children = dtd->last = (xmlNodePtr) ret;
2138 } else {
2139 dtd->last->next = (xmlNodePtr) ret;
2140 ret->prev = dtd->last;
2141 dtd->last = (xmlNodePtr) ret;
2142 }
2143 return(ret);
2144 }
2145
2146 /**
2147 * xmlFreeAttributeTable:
2148 * @table: An attribute table
2149 *
2150 * Deallocate the memory used by an entities hash table.
2151 */
2152 void
2153 xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2154 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2155 }
2156
2157 #ifdef LIBXML_TREE_ENABLED
2158 /**
2159 * xmlCopyAttribute:
2160 * @attr: An attribute
2161 *
2162 * Build a copy of an attribute.
2163 *
2164 * Returns the new xmlAttributePtr or NULL in case of error.
2165 */
2166 static xmlAttributePtr
2167 xmlCopyAttribute(xmlAttributePtr attr) {
2168 xmlAttributePtr cur;
2169
2170 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2171 if (cur == NULL) {
2172 xmlVErrMemory(NULL, "malloc failed");
2173 return(NULL);
2174 }
2175 memset(cur, 0, sizeof(xmlAttribute));
2176 cur->type = XML_ATTRIBUTE_DECL;
2177 cur->atype = attr->atype;
2178 cur->def = attr->def;
2179 cur->tree = xmlCopyEnumeration(attr->tree);
2180 if (attr->elem != NULL)
2181 cur->elem = xmlStrdup(attr->elem);
2182 if (attr->name != NULL)
2183 cur->name = xmlStrdup(attr->name);
2184 if (attr->prefix != NULL)
2185 cur->prefix = xmlStrdup(attr->prefix);
2186 if (attr->defaultValue != NULL)
2187 cur->defaultValue = xmlStrdup(attr->defaultValue);
2188 return(cur);
2189 }
2190
2191 /**
2192 * xmlCopyAttributeTable:
2193 * @table: An attribute table
2194 *
2195 * Build a copy of an attribute table.
2196 *
2197 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2198 */
2199 xmlAttributeTablePtr
2200 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2201 return((xmlAttributeTablePtr) xmlHashCopy(table,
2202 (xmlHashCopier) xmlCopyAttribute));
2203 }
2204 #endif /* LIBXML_TREE_ENABLED */
2205
2206 #ifdef LIBXML_OUTPUT_ENABLED
2207 /**
2208 * xmlDumpAttributeDecl:
2209 * @buf: the XML buffer output
2210 * @attr: An attribute declaration
2211 *
2212 * This will dump the content of the attribute declaration as an XML
2213 * DTD definition
2214 */
2215 void
2216 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2217 if ((buf == NULL) || (attr == NULL))
2218 return;
2219 xmlBufferWriteChar(buf, "<!ATTLIST ");
2220 xmlBufferWriteCHAR(buf, attr->elem);
2221 xmlBufferWriteChar(buf, " ");
2222 if (attr->prefix != NULL) {
2223 xmlBufferWriteCHAR(buf, attr->prefix);
2224 xmlBufferWriteChar(buf, ":");
2225 }
2226 xmlBufferWriteCHAR(buf, attr->name);
2227 switch (attr->atype) {
2228 case XML_ATTRIBUTE_CDATA:
2229 xmlBufferWriteChar(buf, " CDATA");
2230 break;
2231 case XML_ATTRIBUTE_ID:
2232 xmlBufferWriteChar(buf, " ID");
2233 break;
2234 case XML_ATTRIBUTE_IDREF:
2235 xmlBufferWriteChar(buf, " IDREF");
2236 break;
2237 case XML_ATTRIBUTE_IDREFS:
2238 xmlBufferWriteChar(buf, " IDREFS");
2239 break;
2240 case XML_ATTRIBUTE_ENTITY:
2241 xmlBufferWriteChar(buf, " ENTITY");
2242 break;
2243 case XML_ATTRIBUTE_ENTITIES:
2244 xmlBufferWriteChar(buf, " ENTITIES");
2245 break;
2246 case XML_ATTRIBUTE_NMTOKEN:
2247 xmlBufferWriteChar(buf, " NMTOKEN");
2248 break;
2249 case XML_ATTRIBUTE_NMTOKENS:
2250 xmlBufferWriteChar(buf, " NMTOKENS");
2251 break;
2252 case XML_ATTRIBUTE_ENUMERATION:
2253 xmlBufferWriteChar(buf, " (");
2254 xmlDumpEnumeration(buf, attr->tree);
2255 break;
2256 case XML_ATTRIBUTE_NOTATION:
2257 xmlBufferWriteChar(buf, " NOTATION (");
2258 xmlDumpEnumeration(buf, attr->tree);
2259 break;
2260 default:
2261 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2262 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2263 NULL);
2264 }
2265 switch (attr->def) {
2266 case XML_ATTRIBUTE_NONE:
2267 break;
2268 case XML_ATTRIBUTE_REQUIRED:
2269 xmlBufferWriteChar(buf, " #REQUIRED");
2270 break;
2271 case XML_ATTRIBUTE_IMPLIED:
2272 xmlBufferWriteChar(buf, " #IMPLIED");
2273 break;
2274 case XML_ATTRIBUTE_FIXED:
2275 xmlBufferWriteChar(buf, " #FIXED");
2276 break;
2277 default:
2278 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2279 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2280 NULL);
2281 }
2282 if (attr->defaultValue != NULL) {
2283 xmlBufferWriteChar(buf, " ");
2284 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2285 }
2286 xmlBufferWriteChar(buf, ">\n");
2287 }
2288
2289 /**
2290 * xmlDumpAttributeDeclScan:
2291 * @attr: An attribute declaration
2292 * @buf: the XML buffer output
2293 *
2294 * This is used with the hash scan function - just reverses arguments
2295 */
2296 static void
2297 xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2298 xmlDumpAttributeDecl(buf, attr);
2299 }
2300
2301 /**
2302 * xmlDumpAttributeTable:
2303 * @buf: the XML buffer output
2304 * @table: An attribute table
2305 *
2306 * This will dump the content of the attribute table as an XML DTD definition
2307 */
2308 void
2309 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2310 if ((buf == NULL) || (table == NULL))
2311 return;
2312 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
2313 }
2314 #endif /* LIBXML_OUTPUT_ENABLED */
2315
2316 /************************************************************************
2317 * *
2318 * NOTATIONs *
2319 * *
2320 ************************************************************************/
2321 /**
2322 * xmlFreeNotation:
2323 * @not: A notation
2324 *
2325 * Deallocate the memory used by an notation definition
2326 */
2327 static void
2328 xmlFreeNotation(xmlNotationPtr nota) {
2329 if (nota == NULL) return;
2330 if (nota->name != NULL)
2331 xmlFree((xmlChar *) nota->name);
2332 if (nota->PublicID != NULL)
2333 xmlFree((xmlChar *) nota->PublicID);
2334 if (nota->SystemID != NULL)
2335 xmlFree((xmlChar *) nota->SystemID);
2336 xmlFree(nota);
2337 }
2338
2339
2340 /**
2341 * xmlAddNotationDecl:
2342 * @dtd: pointer to the DTD
2343 * @ctxt: the validation context
2344 * @name: the entity name
2345 * @PublicID: the public identifier or NULL
2346 * @SystemID: the system identifier or NULL
2347 *
2348 * Register a new notation declaration
2349 *
2350 * Returns NULL if not, otherwise the entity
2351 */
2352 xmlNotationPtr
2353 xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
2354 const xmlChar *name,
2355 const xmlChar *PublicID, const xmlChar *SystemID) {
2356 xmlNotationPtr ret;
2357 xmlNotationTablePtr table;
2358
2359 if (dtd == NULL) {
2360 return(NULL);
2361 }
2362 if (name == NULL) {
2363 return(NULL);
2364 }
2365 if ((PublicID == NULL) && (SystemID == NULL)) {
2366 return(NULL);
2367 }
2368
2369 /*
2370 * Create the Notation table if needed.
2371 */
2372 table = (xmlNotationTablePtr) dtd->notations;
2373 if (table == NULL) {
2374 xmlDictPtr dict = NULL;
2375 if (dtd->doc != NULL)
2376 dict = dtd->doc->dict;
2377
2378 dtd->notations = table = xmlHashCreateDict(0, dict);
2379 }
2380 if (table == NULL) {
2381 xmlVErrMemory(ctxt,
2382 "xmlAddNotationDecl: Table creation failed!\n");
2383 return(NULL);
2384 }
2385
2386 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2387 if (ret == NULL) {
2388 xmlVErrMemory(ctxt, "malloc failed");
2389 return(NULL);
2390 }
2391 memset(ret, 0, sizeof(xmlNotation));
2392
2393 /*
2394 * fill the structure.
2395 */
2396 ret->name = xmlStrdup(name);
2397 if (SystemID != NULL)
2398 ret->SystemID = xmlStrdup(SystemID);
2399 if (PublicID != NULL)
2400 ret->PublicID = xmlStrdup(PublicID);
2401
2402 /*
2403 * Validity Check:
2404 * Check the DTD for previous declarations of the ATTLIST
2405 */
2406 if (xmlHashAddEntry(table, name, ret)) {
2407 #ifdef LIBXML_VALID_ENABLED
2408 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2409 "xmlAddNotationDecl: %s already defined\n",
2410 (const char *) name);
2411 #endif /* LIBXML_VALID_ENABLED */
2412 xmlFreeNotation(ret);
2413 return(NULL);
2414 }
2415 return(ret);
2416 }
2417
2418 /**
2419 * xmlFreeNotationTable:
2420 * @table: An notation table
2421 *
2422 * Deallocate the memory used by an entities hash table.
2423 */
2424 void
2425 xmlFreeNotationTable(xmlNotationTablePtr table) {
2426 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2427 }
2428
2429 #ifdef LIBXML_TREE_ENABLED
2430 /**
2431 * xmlCopyNotation:
2432 * @nota: A notation
2433 *
2434 * Build a copy of a notation.
2435 *
2436 * Returns the new xmlNotationPtr or NULL in case of error.
2437 */
2438 static xmlNotationPtr
2439 xmlCopyNotation(xmlNotationPtr nota) {
2440 xmlNotationPtr cur;
2441
2442 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2443 if (cur == NULL) {
2444 xmlVErrMemory(NULL, "malloc failed");
2445 return(NULL);
2446 }
2447 if (nota->name != NULL)
2448 cur->name = xmlStrdup(nota->name);
2449 else
2450 cur->name = NULL;
2451 if (nota->PublicID != NULL)
2452 cur->PublicID = xmlStrdup(nota->PublicID);
2453 else
2454 cur->PublicID = NULL;
2455 if (nota->SystemID != NULL)
2456 cur->SystemID = xmlStrdup(nota->SystemID);
2457 else
2458 cur->SystemID = NULL;
2459 return(cur);
2460 }
2461
2462 /**
2463 * xmlCopyNotationTable:
2464 * @table: A notation table
2465 *
2466 * Build a copy of a notation table.
2467 *
2468 * Returns the new xmlNotationTablePtr or NULL in case of error.
2469 */
2470 xmlNotationTablePtr
2471 xmlCopyNotationTable(xmlNotationTablePtr table) {
2472 return((xmlNotationTablePtr) xmlHashCopy(table,
2473 (xmlHashCopier) xmlCopyNotation));
2474 }
2475 #endif /* LIBXML_TREE_ENABLED */
2476
2477 #ifdef LIBXML_OUTPUT_ENABLED
2478 /**
2479 * xmlDumpNotationDecl:
2480 * @buf: the XML buffer output
2481 * @nota: A notation declaration
2482 *
2483 * This will dump the content the notation declaration as an XML DTD definition
2484 */
2485 void
2486 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2487 if ((buf == NULL) || (nota == NULL))
2488 return;
2489 xmlBufferWriteChar(buf, "<!NOTATION ");
2490 xmlBufferWriteCHAR(buf, nota->name);
2491 if (nota->PublicID != NULL) {
2492 xmlBufferWriteChar(buf, " PUBLIC ");
2493 xmlBufferWriteQuotedString(buf, nota->PublicID);
2494 if (nota->SystemID != NULL) {
2495 xmlBufferWriteChar(buf, " ");
2496 xmlBufferWriteQuotedString(buf, nota->SystemID);
2497 }
2498 } else {
2499 xmlBufferWriteChar(buf, " SYSTEM ");
2500 xmlBufferWriteQuotedString(buf, nota->SystemID);
2501 }
2502 xmlBufferWriteChar(buf, " >\n");
2503 }
2504
2505 /**
2506 * xmlDumpNotationDeclScan:
2507 * @nota: A notation declaration
2508 * @buf: the XML buffer output
2509 *
2510 * This is called with the hash scan function, and just reverses args
2511 */
2512 static void
2513 xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2514 xmlDumpNotationDecl(buf, nota);
2515 }
2516
2517 /**
2518 * xmlDumpNotationTable:
2519 * @buf: the XML buffer output
2520 * @table: A notation table
2521 *
2522 * This will dump the content of the notation table as an XML DTD definition
2523 */
2524 void
2525 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2526 if ((buf == NULL) || (table == NULL))
2527 return;
2528 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
2529 }
2530 #endif /* LIBXML_OUTPUT_ENABLED */
2531
2532 /************************************************************************
2533 * *
2534 * IDs *
2535 * *
2536 ************************************************************************/
2537 /**
2538 * DICT_FREE:
2539 * @str: a string
2540 *
2541 * Free a string if it is not owned by the "dict" dictionary in the
2542 * current scope
2543 */
2544 #define DICT_FREE(str) \
2545 if ((str) && ((!dict) || \
2546 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2547 xmlFree((char *)(str));
2548
2549 /**
2550 * xmlFreeID:
2551 * @not: A id
2552 *
2553 * Deallocate the memory used by an id definition
2554 */
2555 static void
2556 xmlFreeID(xmlIDPtr id) {
2557 xmlDictPtr dict = NULL;
2558
2559 if (id == NULL) return;
2560
2561 if (id->doc != NULL)
2562 dict = id->doc->dict;
2563
2564 if (id->value != NULL)
2565 DICT_FREE(id->value)
2566 if (id->name != NULL)
2567 DICT_FREE(id->name)
2568 xmlFree(id);
2569 }
2570
2571
2572 /**
2573 * xmlAddID:
2574 * @ctxt: the validation context
2575 * @doc: pointer to the document
2576 * @value: the value name
2577 * @attr: the attribute holding the ID
2578 *
2579 * Register a new id declaration
2580 *
2581 * Returns NULL if not, otherwise the new xmlIDPtr
2582 */
2583 xmlIDPtr
2584 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2585 xmlAttrPtr attr) {
2586 xmlIDPtr ret;
2587 xmlIDTablePtr table;
2588
2589 if (doc == NULL) {
2590 return(NULL);
2591 }
2592 if (value == NULL) {
2593 return(NULL);
2594 }
2595 if (attr == NULL) {
2596 return(NULL);
2597 }
2598
2599 /*
2600 * Create the ID table if needed.
2601 */
2602 table = (xmlIDTablePtr) doc->ids;
2603 if (table == NULL) {
2604 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2605 }
2606 if (table == NULL) {
2607 xmlVErrMemory(ctxt,
2608 "xmlAddID: Table creation failed!\n");
2609 return(NULL);
2610 }
2611
2612 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2613 if (ret == NULL) {
2614 xmlVErrMemory(ctxt, "malloc failed");
2615 return(NULL);
2616 }
2617
2618 /*
2619 * fill the structure.
2620 */
2621 ret->value = xmlStrdup(value);
2622 ret->doc = doc;
2623 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2624 /*
2625 * Operating in streaming mode, attr is gonna disapear
2626 */
2627 if (doc->dict != NULL)
2628 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2629 else
2630 ret->name = xmlStrdup(attr->name);
2631 ret->attr = NULL;
2632 } else {
2633 ret->attr = attr;
2634 ret->name = NULL;
2635 }
2636 ret->lineno = xmlGetLineNo(attr->parent);
2637
2638 if (xmlHashAddEntry(table, value, ret) < 0) {
2639 #ifdef LIBXML_VALID_ENABLED
2640 /*
2641 * The id is already defined in this DTD.
2642 */
2643 if (ctxt != NULL) {
2644 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2645 "ID %s already defined\n", value, NULL, NULL);
2646 }
2647 #endif /* LIBXML_VALID_ENABLED */
2648 xmlFreeID(ret);
2649 return(NULL);
2650 }
2651 if (attr != NULL)
2652 attr->atype = XML_ATTRIBUTE_ID;
2653 return(ret);
2654 }
2655
2656 /**
2657 * xmlFreeIDTable:
2658 * @table: An id table
2659 *
2660 * Deallocate the memory used by an ID hash table.
2661 */
2662 void
2663 xmlFreeIDTable(xmlIDTablePtr table) {
2664 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2665 }
2666
2667 /**
2668 * xmlIsID:
2669 * @doc: the document
2670 * @elem: the element carrying the attribute
2671 * @attr: the attribute
2672 *
2673 * Determine whether an attribute is of type ID. In case we have DTD(s)
2674 * then this is done if DTD loading has been requested. In the case
2675 * of HTML documents parsed with the HTML parser, then ID detection is
2676 * done systematically.
2677 *
2678 * Returns 0 or 1 depending on the lookup result
2679 */
2680 int
2681 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2682 if ((attr == NULL) || (attr->name == NULL)) return(0);
2683 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2684 (!strcmp((char *) attr->name, "id")) &&
2685 (!strcmp((char *) attr->ns->prefix, "xml")))
2686 return(1);
2687 if (doc == NULL) return(0);
2688 if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2689 (doc->type != XML_HTML_DOCUMENT_NODE)) {
2690 return(0);
2691 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2692 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2693 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2694 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2695 return(1);
2696 return(0);
2697 } else if (elem == NULL) {
2698 return(0);
2699 } else {
2700 xmlAttributePtr attrDecl = NULL;
2701
2702 xmlChar felem[50], fattr[50];
2703 xmlChar *fullelemname, *fullattrname;
2704
2705 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2706 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2707 (xmlChar *)elem->name;
2708
2709 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2710 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2711 (xmlChar *)attr->name;
2712
2713 if (fullelemname != NULL && fullattrname != NULL) {
2714 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2715 fullattrname);
2716 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2717 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2718 fullattrname);
2719 }
2720
2721 if ((fullattrname != fattr) && (fullattrname != attr->name))
2722 xmlFree(fullattrname);
2723 if ((fullelemname != felem) && (fullelemname != elem->name))
2724 xmlFree(fullelemname);
2725
2726 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2727 return(1);
2728 }
2729 return(0);
2730 }
2731
2732 /**
2733 * xmlRemoveID:
2734 * @doc: the document
2735 * @attr: the attribute
2736 *
2737 * Remove the given attribute from the ID table maintained internally.
2738 *
2739 * Returns -1 if the lookup failed and 0 otherwise
2740 */
2741 int
2742 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2743 xmlIDTablePtr table;
2744 xmlIDPtr id;
2745 xmlChar *ID;
2746
2747 if (doc == NULL) return(-1);
2748 if (attr == NULL) return(-1);
2749
2750 table = (xmlIDTablePtr) doc->ids;
2751 if (table == NULL)
2752 return(-1);
2753
2754 ID = xmlNodeListGetString(doc, attr->children, 1);
2755 if (ID == NULL)
2756 return(-1);
2757
2758 id = xmlHashLookup(table, ID);
2759 if (id == NULL || id->attr != attr) {
2760 xmlFree(ID);
2761 return(-1);
2762 }
2763
2764 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
2765 xmlFree(ID);
2766 attr->atype = 0;
2767 return(0);
2768 }
2769
2770 /**
2771 * xmlGetID:
2772 * @doc: pointer to the document
2773 * @ID: the ID value
2774 *
2775 * Search the attribute declaring the given ID
2776 *
2777 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2778 */
2779 xmlAttrPtr
2780 xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2781 xmlIDTablePtr table;
2782 xmlIDPtr id;
2783
2784 if (doc == NULL) {
2785 return(NULL);
2786 }
2787
2788 if (ID == NULL) {
2789 return(NULL);
2790 }
2791
2792 table = (xmlIDTablePtr) doc->ids;
2793 if (table == NULL)
2794 return(NULL);
2795
2796 id = xmlHashLookup(table, ID);
2797 if (id == NULL)
2798 return(NULL);
2799 if (id->attr == NULL) {
2800 /*
2801 * We are operating on a stream, return a well known reference
2802 * since the attribute node doesn't exist anymore
2803 */
2804 return((xmlAttrPtr) doc);
2805 }
2806 return(id->attr);
2807 }
2808
2809 /************************************************************************
2810 * *
2811 * Refs *
2812 * *
2813 ************************************************************************/
2814 typedef struct xmlRemoveMemo_t
2815 {
2816 xmlListPtr l;
2817 xmlAttrPtr ap;
2818 } xmlRemoveMemo;
2819
2820 typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2821
2822 typedef struct xmlValidateMemo_t
2823 {
2824 xmlValidCtxtPtr ctxt;
2825 const xmlChar *name;
2826 } xmlValidateMemo;
2827
2828 typedef xmlValidateMemo *xmlValidateMemoPtr;
2829
2830 /**
2831 * xmlFreeRef:
2832 * @lk: A list link
2833 *
2834 * Deallocate the memory used by a ref definition
2835 */
2836 static void
2837 xmlFreeRef(xmlLinkPtr lk) {
2838 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2839 if (ref == NULL) return;
2840 if (ref->value != NULL)
2841 xmlFree((xmlChar *)ref->value);
2842 if (ref->name != NULL)
2843 xmlFree((xmlChar *)ref->name);
2844 xmlFree(ref);
2845 }
2846
2847 /**
2848 * xmlFreeRefList:
2849 * @list_ref: A list of references.
2850 *
2851 * Deallocate the memory used by a list of references
2852 */
2853 static void
2854 xmlFreeRefList(xmlListPtr list_ref) {
2855 if (list_ref == NULL) return;
2856 xmlListDelete(list_ref);
2857 }
2858
2859 /**
2860 * xmlWalkRemoveRef:
2861 * @data: Contents of current link
2862 * @user: Value supplied by the user
2863 *
2864 * Returns 0 to abort the walk or 1 to continue
2865 */
2866 static int
2867 xmlWalkRemoveRef(const void *data, const void *user)
2868 {
2869 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2870 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2871 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2872
2873 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2874 xmlListRemoveFirst(ref_list, (void *)data);
2875 return 0;
2876 }
2877 return 1;
2878 }
2879
2880 /**
2881 * xmlDummyCompare
2882 * @data0: Value supplied by the user
2883 * @data1: Value supplied by the user
2884 *
2885 * Do nothing, return 0. Used to create unordered lists.
2886 */
2887 static int
2888 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2889 const void *data1 ATTRIBUTE_UNUSED)
2890 {
2891 return (0);
2892 }
2893
2894 /**
2895 * xmlAddRef:
2896 * @ctxt: the validation context
2897 * @doc: pointer to the document
2898 * @value: the value name
2899 * @attr: the attribute holding the Ref
2900 *
2901 * Register a new ref declaration
2902 *
2903 * Returns NULL if not, otherwise the new xmlRefPtr
2904 */
2905 xmlRefPtr
2906 xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2907 xmlAttrPtr attr) {
2908 xmlRefPtr ret;
2909 xmlRefTablePtr table;
2910 xmlListPtr ref_list;
2911
2912 if (doc == NULL) {
2913 return(NULL);
2914 }
2915 if (value == NULL) {
2916 return(NULL);
2917 }
2918 if (attr == NULL) {
2919 return(NULL);
2920 }
2921
2922 /*
2923 * Create the Ref table if needed.
2924 */
2925 table = (xmlRefTablePtr) doc->refs;
2926 if (table == NULL) {
2927 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2928 }
2929 if (table == NULL) {
2930 xmlVErrMemory(ctxt,
2931 "xmlAddRef: Table creation failed!\n");
2932 return(NULL);
2933 }
2934
2935 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2936 if (ret == NULL) {
2937 xmlVErrMemory(ctxt, "malloc failed");
2938 return(NULL);
2939 }
2940
2941 /*
2942 * fill the structure.
2943 */
2944 ret->value = xmlStrdup(value);
2945 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2946 /*
2947 * Operating in streaming mode, attr is gonna disapear
2948 */
2949 ret->name = xmlStrdup(attr->name);
2950 ret->attr = NULL;
2951 } else {
2952 ret->name = NULL;
2953 ret->attr = attr;
2954 }
2955 ret->lineno = xmlGetLineNo(attr->parent);
2956
2957 /* To add a reference :-
2958 * References are maintained as a list of references,
2959 * Lookup the entry, if no entry create new nodelist
2960 * Add the owning node to the NodeList
2961 * Return the ref
2962 */
2963
2964 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2965 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
2966 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2967 "xmlAddRef: Reference list creation failed!\n",
2968 NULL);
2969 goto failed;
2970 }
2971 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2972 xmlListDelete(ref_list);
2973 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2974 "xmlAddRef: Reference list insertion failed!\n",
2975 NULL);
2976 goto failed;
2977 }
2978 }
2979 if (xmlListAppend(ref_list, ret) != 0) {
2980 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2981 "xmlAddRef: Reference list insertion failed!\n",
2982 NULL);
2983 goto failed;
2984 }
2985 return(ret);
2986 failed:
2987 if (ret != NULL) {
2988 if (ret->value != NULL)
2989 xmlFree((char *)ret->value);
2990 if (ret->name != NULL)
2991 xmlFree((char *)ret->name);
2992 xmlFree(ret);
2993 }
2994 return(NULL);
2995 }
2996
2997 /**
2998 * xmlFreeRefTable:
2999 * @table: An ref table
3000 *
3001 * Deallocate the memory used by an Ref hash table.
3002 */
3003 void
3004 xmlFreeRefTable(xmlRefTablePtr table) {
3005 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
3006 }
3007
3008 /**
3009 * xmlIsRef:
3010 * @doc: the document
3011 * @elem: the element carrying the attribute
3012 * @attr: the attribute
3013 *
3014 * Determine whether an attribute is of type Ref. In case we have DTD(s)
3015 * then this is simple, otherwise we use an heuristic: name Ref (upper
3016 * or lowercase).
3017 *
3018 * Returns 0 or 1 depending on the lookup result
3019 */
3020 int
3021 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3022 if (attr == NULL)
3023 return(0);
3024 if (doc == NULL) {
3025 doc = attr->doc;
3026 if (doc == NULL) return(0);
3027 }
3028
3029 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3030 return(0);
3031 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3032 /* TODO @@@ */
3033 return(0);
3034 } else {
3035 xmlAttributePtr attrDecl;
3036
3037 if (elem == NULL) return(0);
3038 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3039 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3040 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3041 elem->name, attr->name);
3042
3043 if ((attrDecl != NULL) &&
3044 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3045 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3046 return(1);
3047 }
3048 return(0);
3049 }
3050
3051 /**
3052 * xmlRemoveRef:
3053 * @doc: the document
3054 * @attr: the attribute
3055 *
3056 * Remove the given attribute from the Ref table maintained internally.
3057 *
3058 * Returns -1 if the lookup failed and 0 otherwise
3059 */
3060 int
3061 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
3062 xmlListPtr ref_list;
3063 xmlRefTablePtr table;
3064 xmlChar *ID;
3065 xmlRemoveMemo target;
3066
3067 if (doc == NULL) return(-1);
3068 if (attr == NULL) return(-1);
3069
3070 table = (xmlRefTablePtr) doc->refs;
3071 if (table == NULL)
3072 return(-1);
3073
3074 ID = xmlNodeListGetString(doc, attr->children, 1);
3075 if (ID == NULL)
3076 return(-1);
3077
3078 ref_list = xmlHashLookup(table, ID);
3079 if(ref_list == NULL) {
3080 xmlFree(ID);
3081 return (-1);
3082 }
3083
3084 /* At this point, ref_list refers to a list of references which
3085 * have the same key as the supplied attr. Our list of references
3086 * is ordered by reference address and we don't have that information
3087 * here to use when removing. We'll have to walk the list and
3088 * check for a matching attribute, when we find one stop the walk
3089 * and remove the entry.
3090 * The list is ordered by reference, so that means we don't have the
3091 * key. Passing the list and the reference to the walker means we
3092 * will have enough data to be able to remove the entry.
3093 */
3094 target.l = ref_list;
3095 target.ap = attr;
3096
3097 /* Remove the supplied attr from our list */
3098 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3099
3100 /*If the list is empty then remove the list entry in the hash */
3101 if (xmlListEmpty(ref_list))
3102 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3103 xmlFreeRefList);
3104 xmlFree(ID);
3105 return(0);
3106 }
3107
3108 /**
3109 * xmlGetRefs:
3110 * @doc: pointer to the document
3111 * @ID: the ID value
3112 *
3113 * Find the set of references for the supplied ID.
3114 *
3115 * Returns NULL if not found, otherwise node set for the ID.
3116 */
3117 xmlListPtr
3118 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
3119 xmlRefTablePtr table;
3120
3121 if (doc == NULL) {
3122 return(NULL);
3123 }
3124
3125 if (ID == NULL) {
3126 return(NULL);
3127 }
3128
3129 table = (xmlRefTablePtr) doc->refs;
3130 if (table == NULL)
3131 return(NULL);
3132
3133 return (xmlHashLookup(table, ID));
3134 }
3135
3136 /************************************************************************
3137 * *
3138 * Routines for validity checking *
3139 * *
3140 ************************************************************************/
3141
3142 /**
3143 * xmlGetDtdElementDesc:
3144 * @dtd: a pointer to the DtD to search
3145 * @name: the element name
3146 *
3147 * Search the DTD for the description of this element
3148 *
3149 * returns the xmlElementPtr if found or NULL
3150 */
3151
3152 xmlElementPtr
3153 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3154 xmlElementTablePtr table;
3155 xmlElementPtr cur;
3156 xmlChar *uqname = NULL, *prefix = NULL;
3157
3158 if ((dtd == NULL) || (name == NULL)) return(NULL);
3159 if (dtd->elements == NULL)
3160 return(NULL);
3161 table = (xmlElementTablePtr) dtd->elements;
3162
3163 uqname = xmlSplitQName2(name, &prefix);
3164 if (uqname != NULL)
3165 name = uqname;
3166 cur = xmlHashLookup2(table, name, prefix);
3167 if (prefix != NULL) xmlFree(prefix);
3168 if (uqname != NULL) xmlFree(uqname);
3169 return(cur);
3170 }
3171 /**
3172 * xmlGetDtdElementDesc2:
3173 * @dtd: a pointer to the DtD to search
3174 * @name: the element name
3175 * @create: create an empty description if not found
3176 *
3177 * Search the DTD for the description of this element
3178 *
3179 * returns the xmlElementPtr if found or NULL
3180 */
3181
3182 static xmlElementPtr
3183 xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3184 xmlElementTablePtr table;
3185 xmlElementPtr cur;
3186 xmlChar *uqname = NULL, *prefix = NULL;
3187
3188 if (dtd == NULL) return(NULL);
3189 if (dtd->elements == NULL) {
3190 xmlDictPtr dict = NULL;
3191
3192 if (dtd->doc != NULL)
3193 dict = dtd->doc->dict;
3194
3195 if (!create)
3196 return(NULL);
3197 /*
3198 * Create the Element table if needed.
3199 */
3200 table = (xmlElementTablePtr) dtd->elements;
3201 if (table == NULL) {
3202 table = xmlHashCreateDict(0, dict);
3203 dtd->elements = (void *) table;
3204 }
3205 if (table == NULL) {
3206 xmlVErrMemory(NULL, "element table allocation failed");
3207 return(NULL);
3208 }
3209 }
3210 table = (xmlElementTablePtr) dtd->elements;
3211
3212 uqname = xmlSplitQName2(name, &prefix);
3213 if (uqname != NULL)
3214 name = uqname;
3215 cur = xmlHashLookup2(table, name, prefix);
3216 if ((cur == NULL) && (create)) {
3217 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3218 if (cur == NULL) {
3219 xmlVErrMemory(NULL, "malloc failed");
3220 return(NULL);
3221 }
3222 memset(cur, 0, sizeof(xmlElement));
3223 cur->type = XML_ELEMENT_DECL;
3224
3225 /*
3226 * fill the structure.
3227 */
3228 cur->name = xmlStrdup(name);
3229 cur->prefix = xmlStrdup(prefix);
3230 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3231
3232 xmlHashAddEntry2(table, name, prefix, cur);
3233 }
3234 if (prefix != NULL) xmlFree(prefix);
3235 if (uqname != NULL) xmlFree(uqname);
3236 return(cur);
3237 }
3238
3239 /**
3240 * xmlGetDtdQElementDesc:
3241 * @dtd: a pointer to the DtD to search
3242 * @name: the element name
3243 * @prefix: the element namespace prefix
3244 *
3245 * Search the DTD for the description of this element
3246 *
3247 * returns the xmlElementPtr if found or NULL
3248 */
3249
3250 xmlElementPtr
3251 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3252 const xmlChar *prefix) {
3253 xmlElementTablePtr table;
3254
3255 if (dtd == NULL) return(NULL);
3256 if (dtd->elements == NULL) return(NULL);
3257 table = (xmlElementTablePtr) dtd->elements;
3258
3259 return(xmlHashLookup2(table, name, prefix));
3260 }
3261
3262 /**
3263 * xmlGetDtdAttrDesc:
3264 * @dtd: a pointer to the DtD to search
3265 * @elem: the element name
3266 * @name: the attribute name
3267 *
3268 * Search the DTD for the description of this attribute on
3269 * this element.
3270 *
3271 * returns the xmlAttributePtr if found or NULL
3272 */
3273
3274 xmlAttributePtr
3275 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3276 xmlAttributeTablePtr table;
3277 xmlAttributePtr cur;
3278 xmlChar *uqname = NULL, *prefix = NULL;
3279
3280 if (dtd == NULL) return(NULL);
3281 if (dtd->attributes == NULL) return(NULL);
3282
3283 table = (xmlAttributeTablePtr) dtd->attributes;
3284 if (table == NULL)
3285 return(NULL);
3286
3287 uqname = xmlSplitQName2(name, &prefix);
3288
3289 if (uqname != NULL) {
3290 cur = xmlHashLookup3(table, uqname, prefix, elem);
3291 if (prefix != NULL) xmlFree(prefix);
3292 if (uqname != NULL) xmlFree(uqname);
3293 } else
3294 cur = xmlHashLookup3(table, name, NULL, elem);
3295 return(cur);
3296 }
3297
3298 /**
3299 * xmlGetDtdQAttrDesc:
3300 * @dtd: a pointer to the DtD to search
3301 * @elem: the element name
3302 * @name: the attribute name
3303 * @prefix: the attribute namespace prefix
3304 *
3305 * Search the DTD for the description of this qualified attribute on
3306 * this element.
3307 *
3308 * returns the xmlAttributePtr if found or NULL
3309 */
3310
3311 xmlAttributePtr
3312 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3313 const xmlChar *prefix) {
3314 xmlAttributeTablePtr table;
3315
3316 if (dtd == NULL) return(NULL);
3317 if (dtd->attributes == NULL) return(NULL);
3318 table = (xmlAttributeTablePtr) dtd->attributes;
3319
3320 return(xmlHashLookup3(table, name, prefix, elem));
3321 }
3322
3323 /**
3324 * xmlGetDtdNotationDesc:
3325 * @dtd: a pointer to the DtD to search
3326 * @name: the notation name
3327 *
3328 * Search the DTD for the description of this notation
3329 *
3330 * returns the xmlNotationPtr if found or NULL
3331 */
3332
3333 xmlNotationPtr
3334 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3335 xmlNotationTablePtr table;
3336
3337 if (dtd == NULL) return(NULL);
3338 if (dtd->notations == NULL) return(NULL);
3339 table = (xmlNotationTablePtr) dtd->notations;
3340
3341 return(xmlHashLookup(table, name));
3342 }
3343
3344 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3345 /**
3346 * xmlValidateNotationUse:
3347 * @ctxt: the validation context
3348 * @doc: the document
3349 * @notationName: the notation name to check
3350 *
3351 * Validate that the given name match a notation declaration.
3352 * - [ VC: Notation Declared ]
3353 *
3354 * returns 1 if valid or 0 otherwise
3355 */
3356
3357 int
3358 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3359 const xmlChar *notationName) {
3360 xmlNotationPtr notaDecl;
3361 if ((doc == NULL) || (doc->intSubset == NULL) ||
3362 (notationName == NULL)) return(-1);
3363
3364 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3365 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3366 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3367
3368 if ((notaDecl == NULL) && (ctxt != NULL)) {
3369 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3370 "NOTATION %s is not declared\n",
3371 notationName, NULL, NULL);
3372 return(0);
3373 }
3374 return(1);
3375 }
3376 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3377
3378 /**
3379 * xmlIsMixedElement:
3380 * @doc: the document
3381 * @name: the element name
3382 *
3383 * Search in the DtDs whether an element accept Mixed content (or ANY)
3384 * basically if it is supposed to accept text childs
3385 *
3386 * returns 0 if no, 1 if yes, and -1 if no element description is available
3387 */
3388
3389 int
3390 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3391 xmlElementPtr elemDecl;
3392
3393 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3394
3395 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3396 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3397 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3398 if (elemDecl == NULL) return(-1);
3399 switch (elemDecl->etype) {
3400 case XML_ELEMENT_TYPE_UNDEFINED:
3401 return(-1);
3402 case XML_ELEMENT_TYPE_ELEMENT:
3403 return(0);
3404 case XML_ELEMENT_TYPE_EMPTY:
3405 /*
3406 * return 1 for EMPTY since we want VC error to pop up
3407 * on <empty> </empty> for example
3408 */
3409 case XML_ELEMENT_TYPE_ANY:
3410 case XML_ELEMENT_TYPE_MIXED:
3411 return(1);
3412 }
3413 return(1);
3414 }
3415
3416 #ifdef LIBXML_VALID_ENABLED
3417
3418 static int
3419 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3420 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3421 /*
3422 * Use the new checks of production [4] [4a] amd [5] of the
3423 * Update 5 of XML-1.0
3424 */
3425 if (((c >= 'a') && (c <= 'z')) ||
3426 ((c >= 'A') && (c <= 'Z')) ||
3427 (c == '_') || (c == ':') ||
3428 ((c >= 0xC0) && (c <= 0xD6)) ||
3429 ((c >= 0xD8) && (c <= 0xF6)) ||
3430 ((c >= 0xF8) && (c <= 0x2FF)) ||
3431 ((c >= 0x370) && (c <= 0x37D)) ||
3432 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3433 ((c >= 0x200C) && (c <= 0x200D)) ||
3434 ((c >= 0x2070) && (c <= 0x218F)) ||
3435 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3436 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3437 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3438 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3439 ((c >= 0x10000) && (c <= 0xEFFFF)))
3440 return(1);
3441 } else {
3442 if (IS_LETTER(c) || (c == '_') || (c == ':'))
3443 return(1);
3444 }
3445 return(0);
3446 }
3447
3448 static int
3449 xmlIsDocNameChar(xmlDocPtr doc, int c) {
3450 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3451 /*
3452 * Use the new checks of production [4] [4a] amd [5] of the
3453 * Update 5 of XML-1.0
3454 */
3455 if (((c >= 'a') && (c <= 'z')) ||
3456 ((c >= 'A') && (c <= 'Z')) ||
3457 ((c >= '0') && (c <= '9')) || /* !start */
3458 (c == '_') || (c == ':') ||
3459 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3460 ((c >= 0xC0) && (c <= 0xD6)) ||
3461 ((c >= 0xD8) && (c <= 0xF6)) ||
3462 ((c >= 0xF8) && (c <= 0x2FF)) ||
3463 ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3464 ((c >= 0x370) && (c <= 0x37D)) ||
3465 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3466 ((c >= 0x200C) && (c <= 0x200D)) ||
3467 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3468 ((c >= 0x2070) && (c <= 0x218F)) ||
3469 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3470 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3471 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3472 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3473 ((c >= 0x10000) && (c <= 0xEFFFF)))
3474 return(1);
3475 } else {
3476 if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3477 (c == '.') || (c == '-') ||
3478 (c == '_') || (c == ':') ||
3479 (IS_COMBINING(c)) ||
3480 (IS_EXTENDER(c)))
3481 return(1);
3482 }
3483 return(0);
3484 }
3485
3486 /**
3487 * xmlValidateNameValue:
3488 * @doc: pointer to the document or NULL
3489 * @value: an Name value
3490 *
3491 * Validate that the given value match Name production
3492 *
3493 * returns 1 if valid or 0 otherwise
3494 */
3495
3496 static int
3497 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3498 const xmlChar *cur;
3499 int val, len;
3500
3501 if (value == NULL) return(0);
3502 cur = value;
3503 val = xmlStringCurrentChar(NULL, cur, &len);
3504 cur += len;
3505 if (!xmlIsDocNameStartChar(doc, val))
3506 return(0);
3507
3508 val = xmlStringCurrentChar(NULL, cur, &len);
3509 cur += len;
3510 while (xmlIsDocNameChar(doc, val)) {
3511 val = xmlStringCurrentChar(NULL, cur, &len);
3512 cur += len;
3513 }
3514
3515 if (val != 0) return(0);
3516
3517 return(1);
3518 }
3519
3520 /**
3521 * xmlValidateNameValue:
3522 * @value: an Name value
3523 *
3524 * Validate that the given value match Name production
3525 *
3526 * returns 1 if valid or 0 otherwise
3527 */
3528
3529 int
3530 xmlValidateNameValue(const xmlChar *value) {
3531 return(xmlValidateNameValueInternal(NULL, value));
3532 }
3533
3534 /**
3535 * xmlValidateNamesValueInternal:
3536 * @doc: pointer to the document or NULL
3537 * @value: an Names value
3538 *
3539 * Validate that the given value match Names production
3540 *
3541 * returns 1 if valid or 0 otherwise
3542 */
3543
3544 static int
3545 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3546 const xmlChar *cur;
3547 int val, len;
3548
3549 if (value == NULL) return(0);
3550 cur = value;
3551 val = xmlStringCurrentChar(NULL, cur, &len);
3552 cur += len;
3553
3554 if (!xmlIsDocNameStartChar(doc, val))
3555 return(0);
3556
3557 val = xmlStringCurrentChar(NULL, cur, &len);
3558 cur += len;
3559 while (xmlIsDocNameChar(doc, val)) {
3560 val = xmlStringCurrentChar(NULL, cur, &len);
3561 cur += len;
3562 }
3563
3564 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3565 while (val == 0x20) {
3566 while (val == 0x20) {
3567 val = xmlStringCurrentChar(NULL, cur, &len);
3568 cur += len;
3569 }
3570
3571 if (!xmlIsDocNameStartChar(doc, val))
3572 return(0);
3573
3574 val = xmlStringCurrentChar(NULL, cur, &len);
3575 cur += len;
3576
3577 while (xmlIsDocNameChar(doc, val)) {
3578 val = xmlStringCurrentChar(NULL, cur, &len);
3579 cur += len;
3580 }
3581 }
3582
3583 if (val != 0) return(0);
3584
3585 return(1);
3586 }
3587
3588 /**
3589 * xmlValidateNamesValue:
3590 * @value: an Names value
3591 *
3592 * Validate that the given value match Names production
3593 *
3594 * returns 1 if valid or 0 otherwise
3595 */
3596
3597 int
3598 xmlValidateNamesValue(const xmlChar *value) {
3599 return(xmlValidateNamesValueInternal(NULL, value));
3600 }
3601
3602 /**
3603 * xmlValidateNmtokenValueInternal:
3604 * @doc: pointer to the document or NULL
3605 * @value: an Nmtoken value
3606 *
3607 * Validate that the given value match Nmtoken production
3608 *
3609 * [ VC: Name Token ]
3610 *
3611 * returns 1 if valid or 0 otherwise
3612 */
3613
3614 static int
3615 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3616 const xmlChar *cur;
3617 int val, len;
3618
3619 if (value == NULL) return(0);
3620 cur = value;
3621 val = xmlStringCurrentChar(NULL, cur, &len);
3622 cur += len;
3623
3624 if (!xmlIsDocNameChar(doc, val))
3625 return(0);
3626
3627 val = xmlStringCurrentChar(NULL, cur, &len);
3628 cur += len;
3629 while (xmlIsDocNameChar(doc, val)) {
3630 val = xmlStringCurrentChar(NULL, cur, &len);
3631 cur += len;
3632 }
3633
3634 if (val != 0) return(0);
3635
3636 return(1);
3637 }
3638
3639 /**
3640 * xmlValidateNmtokenValue:
3641 * @value: an Nmtoken value
3642 *
3643 * Validate that the given value match Nmtoken production
3644 *
3645 * [ VC: Name Token ]
3646 *
3647 * returns 1 if valid or 0 otherwise
3648 */
3649
3650 int
3651 xmlValidateNmtokenValue(const xmlChar *value) {
3652 return(xmlValidateNmtokenValueInternal(NULL, value));
3653 }
3654
3655 /**
3656 * xmlValidateNmtokensValueInternal:
3657 * @doc: pointer to the document or NULL
3658 * @value: an Nmtokens value
3659 *
3660 * Validate that the given value match Nmtokens production
3661 *
3662 * [ VC: Name Token ]
3663 *
3664 * returns 1 if valid or 0 otherwise
3665 */
3666
3667 static int
3668 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3669 const xmlChar *cur;
3670 int val, len;
3671
3672 if (value == NULL) return(0);
3673 cur = value;
3674 val = xmlStringCurrentChar(NULL, cur, &len);
3675 cur += len;
3676
3677 while (IS_BLANK(val)) {
3678 val = xmlStringCurrentChar(NULL, cur, &len);
3679 cur += len;
3680 }
3681
3682 if (!xmlIsDocNameChar(doc, val))
3683 return(0);
3684
3685 while (xmlIsDocNameChar(doc, val)) {
3686 val = xmlStringCurrentChar(NULL, cur, &len);
3687 cur += len;
3688 }
3689
3690 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3691 while (val == 0x20) {
3692 while (val == 0x20) {
3693 val = xmlStringCurrentChar(NULL, cur, &len);
3694 cur += len;
3695 }
3696 if (val == 0) return(1);
3697
3698 if (!xmlIsDocNameChar(doc, val))
3699 return(0);
3700
3701 val = xmlStringCurrentChar(NULL, cur, &len);
3702 cur += len;
3703