blob: 3ece0a1230b2a78a7a5be9f930a7c6d21b7d09f2 [file] [log] [blame]
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001/*
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@w3.org
8 */
9
Daniel Veillard7f7d1111999-09-22 09:46:25 +000010#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000011#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#else
13#include "config.h"
14#endif
15
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000016#include <stdio.h>
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000017#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018
19#ifdef HAVE_STDLIB_H
20#include <stdlib.h>
21#endif
22
Daniel Veillard6454aec1999-09-02 22:04:43 +000023#include "xmlmemory.h"
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000024#include "valid.h"
25#include "parser.h"
Daniel Veillardb05deb71999-08-10 19:04:08 +000026#include "parserInternals.h"
27
Daniel Veillarddbfd6411999-12-28 16:35:14 +000028/* TODO: use hash table for accesses to elem and attribute dedinitions */
29
Daniel Veillardb05deb71999-08-10 19:04:08 +000030#define VERROR \
31 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
32
33#define VWARNING \
34 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
35
36#define CHECK_DTD \
37 if (doc == NULL) return(0); \
38 else if (doc->intSubset == NULL) return(0)
39
Daniel Veillarddd6b3671999-09-23 22:19:22 +000040xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
41xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000042
43/****************************************************************
44 * *
45 * Util functions for data allocation/deallocation *
46 * *
47 ****************************************************************/
48
49/**
50 * xmlNewElementContent:
51 * @name: the subelement name or NULL
52 * @type: the type of element content decl
53 *
54 * Allocate an element content structure.
55 *
Daniel Veillard1e346af1999-02-22 10:33:01 +000056 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000057 */
58xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +000059xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000060 xmlElementContentPtr ret;
61
62 switch(type) {
63 case XML_ELEMENT_CONTENT_ELEMENT:
64 if (name == NULL) {
65 fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
66 }
67 break;
68 case XML_ELEMENT_CONTENT_PCDATA:
69 case XML_ELEMENT_CONTENT_SEQ:
70 case XML_ELEMENT_CONTENT_OR:
71 if (name != NULL) {
72 fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
73 }
74 break;
75 default:
76 fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
Daniel Veillard0142b842000-01-14 14:45:24 +000077 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000078 }
Daniel Veillard6454aec1999-09-02 22:04:43 +000079 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000080 if (ret == NULL) {
81 fprintf(stderr, "xmlNewElementContent : out of memory!\n");
82 return(NULL);
83 }
84 ret->type = type;
85 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +000086 if (name != NULL)
87 ret->name = xmlStrdup(name);
88 else
89 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +000090 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000091 return(ret);
92}
93
94/**
Daniel Veillard3b9def11999-01-31 22:15:06 +000095 * xmlCopyElementContent:
96 * @content: An element content pointer.
97 *
98 * Build a copy of an element content description.
99 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000100 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000101 */
102xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000103xmlCopyElementContent(xmlElementContentPtr cur) {
104 xmlElementContentPtr ret;
105
106 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000107 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000108 if (ret == NULL) {
109 fprintf(stderr, "xmlCopyElementContent : out of memory\n");
110 return(NULL);
111 }
112 ret->ocur = cur->ocur;
113 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
114 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000115 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000116}
117
118/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000119 * xmlFreeElementContent:
120 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000121 *
122 * Free an element content structure. This is a recursive call !
123 */
124void
125xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000126 if (cur == NULL) return;
127 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
128 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000129 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000130 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000131 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000132}
133
Daniel Veillard1899e851999-02-01 12:18:54 +0000134/**
135 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000136 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000137 * @content: An element table
138 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
139 *
140 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000141 */
142void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000143xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000144 if (content == NULL) return;
145
Daniel Veillard5099ae81999-04-21 20:12:07 +0000146 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000147 switch (content->type) {
148 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000149 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000150 break;
151 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000152 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000153 break;
154 case XML_ELEMENT_CONTENT_SEQ:
155 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
156 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000157 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000158 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000159 xmlDumpElementContent(buf, content->c1, 0);
160 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000161 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000162 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000163 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000164 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000165 break;
166 case XML_ELEMENT_CONTENT_OR:
167 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
168 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000169 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000170 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000171 xmlDumpElementContent(buf, content->c1, 0);
172 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000173 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000174 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000175 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000176 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000177 break;
178 default:
179 fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
180 content->type);
181 }
182 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000183 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000184 switch (content->ocur) {
185 case XML_ELEMENT_CONTENT_ONCE:
186 break;
187 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000188 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000189 break;
190 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000191 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000192 break;
193 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000194 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000195 break;
196 }
197}
198
Daniel Veillardb05deb71999-08-10 19:04:08 +0000199/**
200 * xmlSprintfElementContent:
201 * @buf: an output buffer
202 * @content: An element table
203 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
204 *
205 * This will dump the content of the element content definition
206 * Intended just for the debug routine
207 */
208void
209xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
210 if (content == NULL) return;
211 if (glob) strcat(buf, "(");
212 switch (content->type) {
213 case XML_ELEMENT_CONTENT_PCDATA:
214 strcat(buf, "#PCDATA");
215 break;
216 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000217 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000218 break;
219 case XML_ELEMENT_CONTENT_SEQ:
220 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
221 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
222 xmlSprintfElementContent(buf, content->c1, 1);
223 else
224 xmlSprintfElementContent(buf, content->c1, 0);
225 strcat(buf, " , ");
226 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
227 xmlSprintfElementContent(buf, content->c2, 1);
228 else
229 xmlSprintfElementContent(buf, content->c2, 0);
230 break;
231 case XML_ELEMENT_CONTENT_OR:
232 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
233 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
234 xmlSprintfElementContent(buf, content->c1, 1);
235 else
236 xmlSprintfElementContent(buf, content->c1, 0);
237 strcat(buf, " | ");
238 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
239 xmlSprintfElementContent(buf, content->c2, 1);
240 else
241 xmlSprintfElementContent(buf, content->c2, 0);
242 break;
243 }
244 if (glob)
245 strcat(buf, ")");
246 switch (content->ocur) {
247 case XML_ELEMENT_CONTENT_ONCE:
248 break;
249 case XML_ELEMENT_CONTENT_OPT:
250 strcat(buf, "?");
251 break;
252 case XML_ELEMENT_CONTENT_MULT:
253 strcat(buf, "*");
254 break;
255 case XML_ELEMENT_CONTENT_PLUS:
256 strcat(buf, "+");
257 break;
258 }
259}
260
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000261/****************************************************************
262 * *
263 * Registration of DTD declarations *
264 * *
265 ****************************************************************/
266
Daniel Veillard3b9def11999-01-31 22:15:06 +0000267/**
268 * xmlCreateElementTable:
269 *
270 * create and initialize an empty element hash table.
271 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000272 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000273 */
274xmlElementTablePtr
275xmlCreateElementTable(void) {
276 xmlElementTablePtr ret;
277
278 ret = (xmlElementTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000279 xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000280 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000281 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000282 (long)sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000283 return(NULL);
284 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000285 ret->max_elements = XML_MIN_ELEMENT_TABLE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000286 ret->nb_elements = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000287 ret->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000288 xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000289 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000290 fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000291 ret->max_elements * (long)sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000292 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000293 return(NULL);
294 }
295 return(ret);
296}
297
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000298
299/**
300 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000301 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000302 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000303 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000304 * @type: the element type
305 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000306 *
307 * Register a new element declaration
308 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000309 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000310 */
311xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000312xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillard51e3b151999-11-12 17:02:31 +0000313 xmlElementTypeVal type, xmlElementContentPtr content) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000314 xmlElementPtr ret, cur;
315 xmlElementTablePtr table;
316 int i;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000317
318 if (dtd == NULL) {
319 fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
320 return(NULL);
321 }
322 if (name == NULL) {
323 fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
324 return(NULL);
325 }
326 switch (type) {
327 case XML_ELEMENT_TYPE_EMPTY:
328 if (content != NULL) {
329 fprintf(stderr,
330 "xmlAddElementDecl: content != NULL for EMPTY\n");
331 return(NULL);
332 }
333 break;
334 case XML_ELEMENT_TYPE_ANY:
335 if (content != NULL) {
336 fprintf(stderr,
337 "xmlAddElementDecl: content != NULL for ANY\n");
338 return(NULL);
339 }
340 break;
341 case XML_ELEMENT_TYPE_MIXED:
342 if (content == NULL) {
343 fprintf(stderr,
344 "xmlAddElementDecl: content == NULL for MIXED\n");
345 return(NULL);
346 }
347 break;
348 case XML_ELEMENT_TYPE_ELEMENT:
349 if (content == NULL) {
350 fprintf(stderr,
351 "xmlAddElementDecl: content == NULL for ELEMENT\n");
352 return(NULL);
353 }
354 break;
355 default:
356 fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
357 return(NULL);
358 }
359
360 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000361 * Create the Element table if needed.
362 */
363 table = dtd->elements;
364 if (table == NULL)
365 table = dtd->elements = xmlCreateElementTable();
366 if (table == NULL) {
367 fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
368 return(NULL);
369 }
370
371 /*
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000372 * Validity Check:
373 * Search the DTD for previous declarations of the ELEMENT
374 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000375 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000376 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000377 if (!xmlStrcmp(cur->name, name)) {
378 /*
379 * The element is already defined in this Dtd.
380 */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000381 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000382 return(NULL);
383 }
384 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000385
386 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000387 * Grow the table, if needed.
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000388 */
Daniel Veillard3b9def11999-01-31 22:15:06 +0000389 if (table->nb_elements >= table->max_elements) {
390 /*
391 * need more elements.
392 */
393 table->max_elements *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000394 table->table = (xmlElementPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000395 xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000396 if (table->table == NULL) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000397 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
398 return(NULL);
399 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000400 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000401 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000402 if (ret == NULL) {
403 fprintf(stderr, "xmlAddElementDecl: out of memory\n");
404 return(NULL);
405 }
406 table->table[table->nb_elements] = ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000407
408 /*
409 * fill the structure.
410 */
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000411 ret->type = type;
412 ret->name = xmlStrdup(name);
Daniel Veillard14fff061999-06-22 21:49:07 +0000413 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000414 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000415 table->nb_elements++;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000416
417 return(ret);
418}
419
Daniel Veillard3b9def11999-01-31 22:15:06 +0000420/**
421 * xmlFreeElement:
422 * @elem: An element
423 *
424 * Deallocate the memory used by an element definition
425 */
426void
427xmlFreeElement(xmlElementPtr elem) {
428 if (elem == NULL) return;
429 xmlFreeElementContent(elem->content);
430 if (elem->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000431 xmlFree((xmlChar *) elem->name);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000432 memset(elem, -1, sizeof(xmlElement));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000433 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000434}
435
436/**
437 * xmlFreeElementTable:
438 * @table: An element table
439 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000440 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000441 */
442void
443xmlFreeElementTable(xmlElementTablePtr table) {
444 int i;
445
446 if (table == NULL) return;
447
448 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000449 xmlFreeElement(table->table[i]);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000450 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000451 xmlFree(table->table);
452 xmlFree(table);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000453}
454
455/**
456 * xmlCopyElementTable:
457 * @table: An element table
458 *
459 * Build a copy of an element table.
460 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000461 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000462 */
463xmlElementTablePtr
464xmlCopyElementTable(xmlElementTablePtr table) {
465 xmlElementTablePtr ret;
466 xmlElementPtr cur, ent;
467 int i;
468
Daniel Veillard6454aec1999-09-02 22:04:43 +0000469 ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000470 if (ret == NULL) {
471 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
472 return(NULL);
473 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000474 ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000475 sizeof(xmlElementPtr));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000476 if (ret->table == NULL) {
477 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000478 xmlFree(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000479 return(NULL);
480 }
481 ret->max_elements = table->max_elements;
482 ret->nb_elements = table->nb_elements;
483 for (i = 0;i < ret->nb_elements;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000484 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000485 if (cur == NULL) {
486 fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000487 xmlFree(ret);
488 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000489 return(NULL);
490 }
491 ret->table[i] = cur;
492 ent = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000493 cur->type = ent->type;
494 if (ent->name != NULL)
495 cur->name = xmlStrdup(ent->name);
496 else
497 cur->name = NULL;
498 cur->content = xmlCopyElementContent(ent->content);
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000499 /* TODO : rebuild the attribute list on the copy */
Daniel Veillardb05deb71999-08-10 19:04:08 +0000500 cur->attributes = NULL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000501 }
502 return(ret);
503}
504
505/**
506 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000507 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000508 * @table: An element table
509 *
510 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000511 */
512void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000513xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard3b9def11999-01-31 22:15:06 +0000514 int i;
515 xmlElementPtr cur;
516
517 if (table == NULL) return;
518
519 for (i = 0;i < table->nb_elements;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000520 cur = table->table[i];
Daniel Veillard3b9def11999-01-31 22:15:06 +0000521 switch (cur->type) {
522 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000523 xmlBufferWriteChar(buf, "<!ELEMENT ");
524 xmlBufferWriteCHAR(buf, cur->name);
525 xmlBufferWriteChar(buf, " EMPTY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000526 break;
527 case XML_ELEMENT_TYPE_ANY:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000528 xmlBufferWriteChar(buf, "<!ELEMENT ");
529 xmlBufferWriteCHAR(buf, cur->name);
530 xmlBufferWriteChar(buf, " ANY>\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000531 break;
532 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000533 xmlBufferWriteChar(buf, "<!ELEMENT ");
534 xmlBufferWriteCHAR(buf, cur->name);
535 xmlBufferWriteChar(buf, " ");
536 xmlDumpElementContent(buf, cur->content, 1);
537 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000538 break;
539 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000540 xmlBufferWriteChar(buf, "<!ELEMENT ");
541 xmlBufferWriteCHAR(buf, cur->name);
542 xmlBufferWriteChar(buf, " ");
543 xmlDumpElementContent(buf, cur->content, 1);
544 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000545 break;
546 default:
547 fprintf(stderr,
548 "xmlDumpElementTable: internal: unknown type %d\n",
549 cur->type);
550 }
551 }
552}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000553
554/**
555 * xmlCreateEnumeration:
556 * @name: the enumeration name or NULL
557 *
558 * create and initialize an enumeration attribute node.
559 *
560 * Returns the xmlEnumerationPtr just created or NULL in case
561 * of error.
562 */
563xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000564xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000565 xmlEnumerationPtr ret;
566
Daniel Veillard6454aec1999-09-02 22:04:43 +0000567 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000568 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000569 fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000570 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000571 return(NULL);
572 }
573
574 if (name != NULL)
575 ret->name = xmlStrdup(name);
576 else
577 ret->name = NULL;
578 ret->next = NULL;
579 return(ret);
580}
581
582/**
583 * xmlFreeEnumeration:
584 * @cur: the tree to free.
585 *
586 * free an enumeration attribute node (recursive).
587 */
588void
589xmlFreeEnumeration(xmlEnumerationPtr cur) {
590 if (cur == NULL) return;
591
592 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
593
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000594 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000595 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000596 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000597}
598
599/**
600 * xmlCopyEnumeration:
601 * @cur: the tree to copy.
602 *
603 * Copy an enumeration attribute node (recursive).
604 *
605 * Returns the xmlEnumerationPtr just created or NULL in case
606 * of error.
607 */
608xmlEnumerationPtr
609xmlCopyEnumeration(xmlEnumerationPtr cur) {
610 xmlEnumerationPtr ret;
611
612 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000613 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000614
615 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
616 else ret->next = NULL;
617
618 return(ret);
619}
620
621/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000622 * xmlDumpEnumeration:
623 * @buf: the XML buffer output
624 * @enum: An enumeration
625 *
626 * This will dump the content of the enumeration
627 */
628void
629xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
630 if (cur == NULL) return;
631
632 xmlBufferWriteCHAR(buf, cur->name);
633 if (cur->next == NULL)
634 xmlBufferWriteChar(buf, ")");
635 else {
636 xmlBufferWriteChar(buf, " | ");
637 xmlDumpEnumeration(buf, cur->next);
638 }
639}
640
641/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000642 * xmlCreateAttributeTable:
643 *
644 * create and initialize an empty attribute hash table.
645 *
646 * Returns the xmlAttributeTablePtr just created or NULL in case
647 * of error.
648 */
649xmlAttributeTablePtr
650xmlCreateAttributeTable(void) {
651 xmlAttributeTablePtr ret;
652
653 ret = (xmlAttributeTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000654 xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000655 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000656 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000657 (long)sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000658 return(NULL);
659 }
660 ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
661 ret->nb_attributes = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000662 ret->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000663 xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000664 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000665 fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +0000666 ret->max_attributes * (long)sizeof(xmlAttributePtr));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000667 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000668 return(NULL);
669 }
670 return(ret);
671}
672
Daniel Veillardb05deb71999-08-10 19:04:08 +0000673/**
674 * xmlScanAttributeDecl:
675 * @dtd: pointer to the DTD
676 * @elem: the element name
677 *
678 * When inserting a new element scan the DtD for existing attributes
679 * for taht element and initialize the Attribute chain
680 *
681 * Returns the pointer to the first attribute decl in the chain,
682 * possibly NULL.
683 */
684xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000685xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000686 xmlAttributePtr ret = NULL;
687 xmlAttributeTablePtr table;
688 int i;
689
690 if (dtd == NULL) {
691 fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
692 return(NULL);
693 }
694 if (elem == NULL) {
695 fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
696 return(NULL);
697 }
698 table = dtd->attributes;
699 if (table == NULL)
700 return(NULL);
701
702 for (i = 0;i < table->nb_attributes;i++) {
703 if (!xmlStrcmp(table->table[i]->elem, elem)) {
704 table->table[i]->next = ret;
705 ret = table->table[i];
706 }
707 }
708 return(ret);
709}
710
711/**
712 * xmlScanIDAttributeDecl:
713 * @ctxt: the validation context
714 * @elem: the element name
715 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000716 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000717 * declared.
718 *
719 * Returns the number of ID attributes found.
720 */
721int
722xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
723 xmlAttributePtr cur;
724 int ret = 0;
725
726 if (elem == NULL) return(0);
727 cur = elem->attributes;
728 while (cur != NULL) {
729 if (cur->type == XML_ATTRIBUTE_ID) {
730 ret ++;
731 if (ret > 1)
732 VERROR(ctxt->userData,
733 "Element %s has too may ID attributes defined : %s\n",
734 elem->name, cur->name);
735 }
736 cur = cur->next;
737 }
738 return(ret);
739}
740
Daniel Veillard1e346af1999-02-22 10:33:01 +0000741
742/**
743 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000744 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000745 * @dtd: pointer to the DTD
746 * @elem: the element name
747 * @name: the attribute name
748 * @type: the attribute type
749 * @def: the attribute default type
750 * @defaultValue: the attribute default value
751 * @tree: if it's an enumeration, the associated list
752 *
753 * Register a new attribute declaration
754 *
755 * Returns NULL if not, othervise the entity
756 */
757xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000758xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
759 const xmlChar *name, xmlAttributeType type,
760 xmlAttributeDefault def, const xmlChar *defaultValue,
Daniel Veillardc26087b1999-08-30 11:23:51 +0000761 xmlEnumerationPtr tree) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000762 xmlAttributePtr ret, cur;
763 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000764 xmlElementPtr elemDef;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000765 xmlChar *rname;
766 xmlChar *ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000767 int i;
768
769 if (dtd == NULL) {
770 fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
771 return(NULL);
772 }
773 if (name == NULL) {
774 fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
775 return(NULL);
776 }
777 if (elem == NULL) {
778 fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
779 return(NULL);
780 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000781 /*
782 * Check the type and possibly the default value.
783 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000784 switch (type) {
785 case XML_ATTRIBUTE_CDATA:
786 break;
787 case XML_ATTRIBUTE_ID:
788 break;
789 case XML_ATTRIBUTE_IDREF:
790 break;
791 case XML_ATTRIBUTE_IDREFS:
792 break;
793 case XML_ATTRIBUTE_ENTITY:
794 break;
795 case XML_ATTRIBUTE_ENTITIES:
796 break;
797 case XML_ATTRIBUTE_NMTOKEN:
798 break;
799 case XML_ATTRIBUTE_NMTOKENS:
800 break;
801 case XML_ATTRIBUTE_ENUMERATION:
802 break;
803 case XML_ATTRIBUTE_NOTATION:
804 break;
805 default:
806 fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
807 return(NULL);
808 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000809 if ((defaultValue != NULL) &&
810 (!xmlValidateAttributeValue(type, defaultValue))) {
811 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
812 elem, name, defaultValue);
813 defaultValue = NULL;
814 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000815
816 /*
817 * Create the Attribute table if needed.
818 */
819 table = dtd->attributes;
820 if (table == NULL)
821 table = dtd->attributes = xmlCreateAttributeTable();
822 if (table == NULL) {
823 fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
824 return(NULL);
825 }
826
827 /*
Daniel Veillard10a2c651999-12-12 13:03:50 +0000828 * Split the full name into a namespace prefix and the tag name
829 */
830 rname = xmlSplitQName(name, &ns);
831
832 /*
Daniel Veillard1e346af1999-02-22 10:33:01 +0000833 * Validity Check:
834 * Search the DTD for previous declarations of the ATTLIST
835 */
836 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000837 cur = table->table[i];
Daniel Veillard10a2c651999-12-12 13:03:50 +0000838 if ((ns != NULL) && (cur->prefix == NULL)) continue;
839 if ((ns == NULL) && (cur->prefix != NULL)) continue;
840 if ((!xmlStrcmp(cur->name, rname)) && (!xmlStrcmp(cur->elem, elem)) &&
841 ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000842 /*
843 * The attribute is already defined in this Dtd.
844 */
Daniel Veillardb96e6431999-08-29 21:02:19 +0000845 VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
846 elem, name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000847 }
848 }
849
850 /*
851 * Grow the table, if needed.
852 */
853 if (table->nb_attributes >= table->max_attributes) {
854 /*
855 * need more attributes.
856 */
857 table->max_attributes *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000858 table->table = (xmlAttributePtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000859 xmlRealloc(table->table, table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000860 sizeof(xmlAttributePtr));
861 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000862 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
863 return(NULL);
864 }
865 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000866 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000867 if (ret == NULL) {
868 fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
869 return(NULL);
870 }
871 table->table[table->nb_attributes] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000872
873 /*
874 * fill the structure.
875 */
876 ret->type = type;
Daniel Veillard10a2c651999-12-12 13:03:50 +0000877 ret->name = rname;
878 ret->prefix = ns;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000879 ret->elem = xmlStrdup(elem);
880 ret->def = def;
881 ret->tree = tree;
882 if (defaultValue != NULL)
883 ret->defaultValue = xmlStrdup(defaultValue);
884 else
885 ret->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000886 elemDef = xmlGetDtdElementDesc(dtd, elem);
887 if (elemDef != NULL) {
888 if ((type == XML_ATTRIBUTE_ID) &&
889 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
890 VERROR(ctxt->userData,
891 "Element %s has too may ID attributes defined : %s\n",
892 elem, name);
893 ret->next = elemDef->attributes;
894 elemDef->attributes = ret;
895 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000896 table->nb_attributes++;
897
898 return(ret);
899}
900
901/**
902 * xmlFreeAttribute:
903 * @elem: An attribute
904 *
905 * Deallocate the memory used by an attribute definition
906 */
907void
908xmlFreeAttribute(xmlAttributePtr attr) {
909 if (attr == NULL) return;
910 if (attr->tree != NULL)
911 xmlFreeEnumeration(attr->tree);
912 if (attr->elem != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000913 xmlFree((xmlChar *) attr->elem);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000914 if (attr->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000915 xmlFree((xmlChar *) attr->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000916 if (attr->defaultValue != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000917 xmlFree((xmlChar *) attr->defaultValue);
Daniel Veillard10a2c651999-12-12 13:03:50 +0000918 if (attr->prefix != NULL)
919 xmlFree((xmlChar *) attr->prefix);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000920 memset(attr, -1, sizeof(xmlAttribute));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000921 xmlFree(attr);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000922}
923
924/**
925 * xmlFreeAttributeTable:
926 * @table: An attribute table
927 *
928 * Deallocate the memory used by an entities hash table.
929 */
930void
931xmlFreeAttributeTable(xmlAttributeTablePtr table) {
932 int i;
933
934 if (table == NULL) return;
935
936 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000937 xmlFreeAttribute(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000938 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000939 xmlFree(table->table);
940 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000941}
942
943/**
944 * xmlCopyAttributeTable:
945 * @table: An attribute table
946 *
947 * Build a copy of an attribute table.
948 *
949 * Returns the new xmlAttributeTablePtr or NULL in case of error.
950 */
951xmlAttributeTablePtr
952xmlCopyAttributeTable(xmlAttributeTablePtr table) {
953 xmlAttributeTablePtr ret;
954 xmlAttributePtr cur, attr;
955 int i;
956
Daniel Veillard6454aec1999-09-02 22:04:43 +0000957 ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000958 if (ret == NULL) {
959 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
960 return(NULL);
961 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000962 ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
Daniel Veillardb05deb71999-08-10 19:04:08 +0000963 sizeof(xmlAttributePtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000964 if (ret->table == NULL) {
965 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000966 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000967 return(NULL);
968 }
969 ret->max_attributes = table->max_attributes;
970 ret->nb_attributes = table->nb_attributes;
971 for (i = 0;i < ret->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000972 attr = table->table[i];
Daniel Veillard6454aec1999-09-02 22:04:43 +0000973 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000974 if (cur == NULL) {
975 fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000976 xmlFree(ret);
977 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000978 return(NULL);
979 }
980 ret->table[i] = cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000981 cur->type = attr->type;
982 cur->def = attr->def;
983 cur->tree = xmlCopyEnumeration(attr->tree);
984 if (attr->elem != NULL)
985 cur->elem = xmlStrdup(attr->elem);
986 else
987 cur->elem = NULL;
988 if (attr->name != NULL)
989 cur->name = xmlStrdup(attr->name);
990 else
991 cur->name = NULL;
992 if (attr->defaultValue != NULL)
993 cur->defaultValue = xmlStrdup(attr->defaultValue);
994 else
995 cur->defaultValue = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000996 /* NEED to rebuild the next chain !!!!!! */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000997 }
998 return(ret);
999}
1000
1001/**
1002 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001003 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001004 * @table: An attribute table
1005 *
1006 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001007 */
1008void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001009xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001010 int i;
1011 xmlAttributePtr cur;
1012
1013 if (table == NULL) return;
1014
1015 for (i = 0;i < table->nb_attributes;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001016 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001017 xmlBufferWriteChar(buf, "<!ATTLIST ");
1018 xmlBufferWriteCHAR(buf, cur->elem);
1019 xmlBufferWriteChar(buf, " ");
1020 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001021 switch (cur->type) {
1022 case XML_ATTRIBUTE_CDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001023 xmlBufferWriteChar(buf, " CDATA");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001024 break;
1025 case XML_ATTRIBUTE_ID:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001026 xmlBufferWriteChar(buf, " ID");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001027 break;
1028 case XML_ATTRIBUTE_IDREF:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001029 xmlBufferWriteChar(buf, " IDREF");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001030 break;
1031 case XML_ATTRIBUTE_IDREFS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001032 xmlBufferWriteChar(buf, " IDREFS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001033 break;
1034 case XML_ATTRIBUTE_ENTITY:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001035 xmlBufferWriteChar(buf, " ENTITY");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001036 break;
1037 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001038 xmlBufferWriteChar(buf, " ENTITIES");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001039 break;
1040 case XML_ATTRIBUTE_NMTOKEN:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001041 xmlBufferWriteChar(buf, " NMTOKEN");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001042 break;
1043 case XML_ATTRIBUTE_NMTOKENS:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001044 xmlBufferWriteChar(buf, " NMTOKENS");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001045 break;
1046 case XML_ATTRIBUTE_ENUMERATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001047 xmlBufferWriteChar(buf, " (");
1048 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001049 break;
1050 case XML_ATTRIBUTE_NOTATION:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001051 xmlBufferWriteChar(buf, " NOTATION (");
1052 xmlDumpEnumeration(buf, cur->tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001053 break;
1054 default:
1055 fprintf(stderr,
1056 "xmlDumpAttributeTable: internal: unknown type %d\n",
1057 cur->type);
1058 }
1059 switch (cur->def) {
1060 case XML_ATTRIBUTE_NONE:
1061 break;
1062 case XML_ATTRIBUTE_REQUIRED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001063 xmlBufferWriteChar(buf, " #REQUIRED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001064 break;
1065 case XML_ATTRIBUTE_IMPLIED:
Daniel Veillard5099ae81999-04-21 20:12:07 +00001066 xmlBufferWriteChar(buf, " #IMPLIED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001067 break;
1068 case XML_ATTRIBUTE_FIXED:
Daniel Veillardb05deb71999-08-10 19:04:08 +00001069 xmlBufferWriteChar(buf, " #FIXED");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001070 break;
1071 default:
1072 fprintf(stderr,
1073 "xmlDumpAttributeTable: internal: unknown default %d\n",
1074 cur->def);
1075 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001076 if (cur->defaultValue != NULL) {
1077 xmlBufferWriteChar(buf, " ");
1078 xmlBufferWriteQuotedString(buf, cur->defaultValue);
1079 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001080 xmlBufferWriteChar(buf, ">\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001081 }
1082}
1083
1084/************************************************************************
1085 * *
1086 * NOTATIONs *
1087 * *
1088 ************************************************************************/
1089/**
1090 * xmlCreateNotationTable:
1091 *
1092 * create and initialize an empty notation hash table.
1093 *
1094 * Returns the xmlNotationTablePtr just created or NULL in case
1095 * of error.
1096 */
1097xmlNotationTablePtr
1098xmlCreateNotationTable(void) {
1099 xmlNotationTablePtr ret;
1100
1101 ret = (xmlNotationTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001102 xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001103 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001104 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001105 (long)sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001106 return(NULL);
1107 }
1108 ret->max_notations = XML_MIN_NOTATION_TABLE;
1109 ret->nb_notations = 0;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001110 ret->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001111 xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001112 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001113 fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +00001114 ret->max_notations * (long)sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001115 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001116 return(NULL);
1117 }
1118 return(ret);
1119}
1120
1121
1122/**
1123 * xmlAddNotationDecl:
1124 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001125 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001126 * @name: the entity name
1127 * @PublicID: the public identifier or NULL
1128 * @SystemID: the system identifier or NULL
1129 *
1130 * Register a new notation declaration
1131 *
1132 * Returns NULL if not, othervise the entity
1133 */
1134xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001135xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1136 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001137 xmlNotationPtr ret, cur;
1138 xmlNotationTablePtr table;
1139 int i;
1140
1141 if (dtd == NULL) {
1142 fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1143 return(NULL);
1144 }
1145 if (name == NULL) {
1146 fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1147 return(NULL);
1148 }
1149 if ((PublicID == NULL) && (SystemID == NULL)) {
1150 fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1151 }
1152
1153 /*
1154 * Create the Notation table if needed.
1155 */
1156 table = dtd->notations;
1157 if (table == NULL)
1158 table = dtd->notations = xmlCreateNotationTable();
1159 if (table == NULL) {
1160 fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1161 return(NULL);
1162 }
1163
1164 /*
1165 * Validity Check:
1166 * Search the DTD for previous declarations of the ATTLIST
1167 */
1168 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001169 cur = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001170 if (!xmlStrcmp(cur->name, name)) {
1171 /*
1172 * The notation is already defined in this Dtd.
1173 */
1174 fprintf(stderr,
1175 "xmlAddNotationDecl: %s already defined\n", name);
1176 }
1177 }
1178
1179 /*
1180 * Grow the table, if needed.
1181 */
1182 if (table->nb_notations >= table->max_notations) {
1183 /*
1184 * need more notations.
1185 */
1186 table->max_notations *= 2;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001187 table->table = (xmlNotationPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001188 xmlRealloc(table->table, table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001189 sizeof(xmlNotationPtr));
1190 if (table->table == NULL) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001191 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1192 return(NULL);
1193 }
1194 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001195 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001196 if (ret == NULL) {
1197 fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1198 return(NULL);
1199 }
1200 table->table[table->nb_notations] = ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001201
1202 /*
1203 * fill the structure.
1204 */
1205 ret->name = xmlStrdup(name);
1206 if (SystemID != NULL)
1207 ret->SystemID = xmlStrdup(SystemID);
1208 else
1209 ret->SystemID = NULL;
1210 if (PublicID != NULL)
1211 ret->PublicID = xmlStrdup(PublicID);
1212 else
1213 ret->PublicID = NULL;
1214 table->nb_notations++;
1215
1216 return(ret);
1217}
1218
1219/**
1220 * xmlFreeNotation:
1221 * @not: A notation
1222 *
1223 * Deallocate the memory used by an notation definition
1224 */
1225void
1226xmlFreeNotation(xmlNotationPtr nota) {
1227 if (nota == NULL) return;
1228 if (nota->name != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001229 xmlFree((xmlChar *) nota->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001230 if (nota->PublicID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001231 xmlFree((xmlChar *) nota->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001232 if (nota->SystemID != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001233 xmlFree((xmlChar *) nota->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001234 memset(nota, -1, sizeof(xmlNotation));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001235 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001236}
1237
1238/**
1239 * xmlFreeNotationTable:
1240 * @table: An notation table
1241 *
1242 * Deallocate the memory used by an entities hash table.
1243 */
1244void
1245xmlFreeNotationTable(xmlNotationTablePtr table) {
1246 int i;
1247
1248 if (table == NULL) return;
1249
1250 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001251 xmlFreeNotation(table->table[i]);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001252 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001253 xmlFree(table->table);
1254 xmlFree(table);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001255}
1256
1257/**
1258 * xmlCopyNotationTable:
1259 * @table: A notation table
1260 *
1261 * Build a copy of a notation table.
1262 *
1263 * Returns the new xmlNotationTablePtr or NULL in case of error.
1264 */
1265xmlNotationTablePtr
1266xmlCopyNotationTable(xmlNotationTablePtr table) {
1267 xmlNotationTablePtr ret;
1268 xmlNotationPtr cur, nota;
1269 int i;
1270
Daniel Veillard6454aec1999-09-02 22:04:43 +00001271 ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001272 if (ret == NULL) {
1273 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1274 return(NULL);
1275 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001276 ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001277 sizeof(xmlNotationPtr));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001278 if (ret->table == NULL) {
1279 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001280 xmlFree(ret);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001281 return(NULL);
1282 }
1283 ret->max_notations = table->max_notations;
1284 ret->nb_notations = table->nb_notations;
1285 for (i = 0;i < ret->nb_notations;i++) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001286 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001287 if (cur == NULL) {
1288 fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001289 xmlFree(ret);
1290 xmlFree(ret->table);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001291 return(NULL);
1292 }
1293 ret->table[i] = cur;
1294 nota = table->table[i];
Daniel Veillard1e346af1999-02-22 10:33:01 +00001295 if (nota->name != NULL)
1296 cur->name = xmlStrdup(nota->name);
1297 else
1298 cur->name = NULL;
1299 if (nota->PublicID != NULL)
1300 cur->PublicID = xmlStrdup(nota->PublicID);
1301 else
1302 cur->PublicID = NULL;
1303 if (nota->SystemID != NULL)
1304 cur->SystemID = xmlStrdup(nota->SystemID);
1305 else
1306 cur->SystemID = NULL;
1307 }
1308 return(ret);
1309}
1310
1311/**
1312 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001313 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001314 * @table: A notation table
1315 *
1316 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001317 */
1318void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001319xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard1e346af1999-02-22 10:33:01 +00001320 int i;
1321 xmlNotationPtr cur;
1322
1323 if (table == NULL) return;
1324
1325 for (i = 0;i < table->nb_notations;i++) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001326 cur = table->table[i];
Daniel Veillard5099ae81999-04-21 20:12:07 +00001327 xmlBufferWriteChar(buf, "<!NOTATION ");
1328 xmlBufferWriteCHAR(buf, cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001329 if (cur->PublicID != NULL) {
Daniel Veillard011b63c1999-06-02 17:44:04 +00001330 xmlBufferWriteChar(buf, " PUBLIC ");
1331 xmlBufferWriteQuotedString(buf, cur->PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001332 if (cur->SystemID != NULL) {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001333 xmlBufferWriteChar(buf, " ");
1334 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001335 }
1336 } else {
Daniel Veillard5099ae81999-04-21 20:12:07 +00001337 xmlBufferWriteChar(buf, " SYSTEM ");
1338 xmlBufferWriteCHAR(buf, cur->SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001339 }
Daniel Veillard5099ae81999-04-21 20:12:07 +00001340 xmlBufferWriteChar(buf, " >\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001341 }
1342}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001343
1344/************************************************************************
1345 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001346 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001347 * *
1348 ************************************************************************/
1349/**
1350 * xmlCreateIDTable:
1351 *
1352 * create and initialize an empty id hash table.
1353 *
1354 * Returns the xmlIDTablePtr just created or NULL in case
1355 * of error.
1356 */
1357xmlIDTablePtr
1358xmlCreateIDTable(void) {
1359 xmlIDTablePtr ret;
1360
1361 ret = (xmlIDTablePtr)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001362 xmlMalloc(sizeof(xmlIDTable));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001363 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001364 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001365 (long)sizeof(xmlIDTable));
1366 return(NULL);
1367 }
1368 ret->max_ids = XML_MIN_NOTATION_TABLE;
1369 ret->nb_ids = 0;
1370 ret->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001371 xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001372 if (ret == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001373 fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001374 ret->max_ids * (long)sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001375 xmlFree(ret);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001376 return(NULL);
1377 }
1378 return(ret);
1379}
1380
1381
1382/**
1383 * xmlAddID:
1384 * @ctxt: the validation context
1385 * @doc: pointer to the document
1386 * @value: the value name
1387 * @attr: the attribute holding the ID
1388 *
1389 * Register a new id declaration
1390 *
1391 * Returns NULL if not, othervise the new xmlIDPtr
1392 */
1393xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001394xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001395 xmlAttrPtr attr) {
1396 xmlIDPtr ret, cur;
1397 xmlIDTablePtr table;
1398 int i;
1399
1400 if (doc == NULL) {
1401 fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1402 return(NULL);
1403 }
1404 if (value == NULL) {
1405 fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1406 return(NULL);
1407 }
1408 if (attr == NULL) {
1409 fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1410 return(NULL);
1411 }
1412
1413 /*
1414 * Create the ID table if needed.
1415 */
1416 table = doc->ids;
1417 if (table == NULL)
1418 table = doc->ids = xmlCreateIDTable();
1419 if (table == NULL) {
1420 fprintf(stderr, "xmlAddID: Table creation failed!\n");
1421 return(NULL);
1422 }
1423
1424 /*
1425 * Validity Check:
1426 * Search the DTD for previous declarations of the ATTLIST
1427 */
1428 for (i = 0;i < table->nb_ids;i++) {
1429 cur = table->table[i];
1430 if (!xmlStrcmp(cur->value, value)) {
1431 /*
1432 * The id is already defined in this Dtd.
1433 */
1434 VERROR(ctxt->userData, "ID %s already defined\n", value);
1435 return(NULL);
1436 }
1437 }
1438
1439 /*
1440 * Grow the table, if needed.
1441 */
1442 if (table->nb_ids >= table->max_ids) {
1443 /*
1444 * need more ids.
1445 */
1446 table->max_ids *= 2;
1447 table->table = (xmlIDPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001448 xmlRealloc(table->table, table->max_ids *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001449 sizeof(xmlIDPtr));
1450 if (table->table == NULL) {
1451 fprintf(stderr, "xmlAddID: out of memory\n");
1452 return(NULL);
1453 }
1454 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001455 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001456 if (ret == NULL) {
1457 fprintf(stderr, "xmlAddID: out of memory\n");
1458 return(NULL);
1459 }
1460 table->table[table->nb_ids] = ret;
1461
1462 /*
1463 * fill the structure.
1464 */
1465 ret->value = xmlStrdup(value);
1466 ret->attr = attr;
1467 table->nb_ids++;
1468
1469 return(ret);
1470}
1471
1472/**
1473 * xmlFreeID:
1474 * @not: A id
1475 *
1476 * Deallocate the memory used by an id definition
1477 */
1478void
1479xmlFreeID(xmlIDPtr id) {
1480 if (id == NULL) return;
1481 if (id->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001482 xmlFree((xmlChar *) id->value);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001483 memset(id, -1, sizeof(xmlID));
Daniel Veillard6454aec1999-09-02 22:04:43 +00001484 xmlFree(id);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001485}
1486
1487/**
1488 * xmlFreeIDTable:
1489 * @table: An id table
1490 *
1491 * Deallocate the memory used by an ID hash table.
1492 */
1493void
1494xmlFreeIDTable(xmlIDTablePtr table) {
1495 int i;
1496
1497 if (table == NULL) return;
1498
1499 for (i = 0;i < table->nb_ids;i++) {
1500 xmlFreeID(table->table[i]);
1501 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001502 xmlFree(table->table);
1503 xmlFree(table);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001504}
1505
1506/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001507 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001508 * @doc: the document
1509 * @elem: the element carrying the attribute
1510 * @attr: the attribute
1511 *
1512 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1513 * then this is simple, otherwise we use an heuristic: name ID (upper
1514 * or lowercase).
1515 *
1516 * Returns 0 or 1 depending on the lookup result
1517 */
1518int
1519xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001520 if (doc == NULL) return(0);
1521 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001522 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1523 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1524 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1525 (attr->name[2] == 0)) return(1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001526 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1527 if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
1528 (!xmlStrcmp(BAD_CAST "name", attr->name)))
1529 return(1);
1530 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001531 } else {
1532 xmlAttributePtr attrDecl;
1533
Daniel Veillard71b656e2000-01-05 14:46:17 +00001534 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001535 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1536 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1537 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1538 attr->name);
1539
Daniel Veillardb96e6431999-08-29 21:02:19 +00001540 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001541 return(1);
1542 }
1543 return(0);
1544}
1545
Daniel Veillardb96e6431999-08-29 21:02:19 +00001546/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001547 * xmlRemoveID
1548 * @doc: the document
1549 * @attr: the attribute
1550 *
1551 * Remove the given attribute from the ID table maintained internally.
1552 *
1553 * Returns -1 if the lookup failed and 0 otherwise
1554 */
1555int
1556xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1557 xmlIDPtr cur;
1558 xmlIDTablePtr table;
1559 int i;
1560
1561 if (doc == NULL) return(-1);
1562 if (attr == NULL) return(-1);
1563 table = doc->ids;
1564 if (table == NULL)
1565 return(-1);
1566
1567 /*
1568 * Search the ID list.
1569 */
1570 for (i = 0;i < table->nb_ids;i++) {
1571 cur = table->table[i];
1572 if (cur->attr == attr) {
1573 table->nb_ids--;
1574 memmove(&table->table[i], &table->table[i+1],
1575 (table->nb_ids - i) * sizeof(xmlIDPtr));
1576 return(0);
1577 }
1578 }
1579 return(-1);
1580}
1581
1582/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001583 * xmlGetID:
1584 * @doc: pointer to the document
1585 * @ID: the ID value
1586 *
1587 * Search the attribute declaring the given ID
1588 *
1589 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1590 */
1591xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001592xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001593 xmlIDPtr cur;
1594 xmlIDTablePtr table;
1595 int i;
1596
1597 if (doc == NULL) {
1598 fprintf(stderr, "xmlGetID: doc == NULL\n");
1599 return(NULL);
1600 }
1601
1602 if (ID == NULL) {
1603 fprintf(stderr, "xmlGetID: ID == NULL\n");
1604 return(NULL);
1605 }
1606
1607 table = doc->ids;
1608 if (table == NULL)
1609 return(NULL);
1610
1611 /*
1612 * Search the ID list.
1613 */
1614 for (i = 0;i < table->nb_ids;i++) {
1615 cur = table->table[i];
1616 if (!xmlStrcmp(cur->value, ID)) {
1617 return(cur->attr);
1618 }
1619 }
1620 return(NULL);
1621}
1622
Daniel Veillard991e63d1999-08-15 23:32:28 +00001623/************************************************************************
1624 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001625 * Refs *
1626 * *
1627 ************************************************************************/
1628/**
1629 * xmlCreateRefTable:
1630 *
1631 * create and initialize an empty ref hash table.
1632 *
1633 * Returns the xmlRefTablePtr just created or NULL in case
1634 * of error.
1635 */
1636xmlRefTablePtr
1637xmlCreateRefTable(void) {
1638 xmlRefTablePtr ret;
1639
1640 ret = (xmlRefTablePtr)
1641 xmlMalloc(sizeof(xmlRefTable));
1642 if (ret == NULL) {
1643 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1644 (long)sizeof(xmlRefTable));
1645 return(NULL);
1646 }
1647 ret->max_refs = XML_MIN_NOTATION_TABLE;
1648 ret->nb_refs = 0;
1649 ret->table = (xmlRefPtr *)
1650 xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1651 if (ret == NULL) {
1652 fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1653 ret->max_refs * (long)sizeof(xmlRef));
1654 xmlFree(ret);
1655 return(NULL);
1656 }
1657 return(ret);
1658}
1659
1660
1661/**
1662 * xmlAddRef:
1663 * @ctxt: the validation context
1664 * @doc: pointer to the document
1665 * @value: the value name
1666 * @attr: the attribute holding the Ref
1667 *
1668 * Register a new ref declaration
1669 *
1670 * Returns NULL if not, othervise the new xmlRefPtr
1671 */
1672xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001673xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001674 xmlAttrPtr attr) {
1675 xmlRefPtr ret;
1676 xmlRefTablePtr table;
1677
1678 if (doc == NULL) {
1679 fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1680 return(NULL);
1681 }
1682 if (value == NULL) {
1683 fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1684 return(NULL);
1685 }
1686 if (attr == NULL) {
1687 fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1688 return(NULL);
1689 }
1690
1691 /*
1692 * Create the Ref table if needed.
1693 */
1694 table = doc->refs;
1695 if (table == NULL)
1696 table = doc->refs = xmlCreateRefTable();
1697 if (table == NULL) {
1698 fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1699 return(NULL);
1700 }
1701
1702 /*
1703 * Grow the table, if needed.
1704 */
1705 if (table->nb_refs >= table->max_refs) {
1706 /*
1707 * need more refs.
1708 */
1709 table->max_refs *= 2;
1710 table->table = (xmlRefPtr *)
1711 xmlRealloc(table->table, table->max_refs *
1712 sizeof(xmlRefPtr));
1713 if (table->table == NULL) {
1714 fprintf(stderr, "xmlAddRef: out of memory\n");
1715 return(NULL);
1716 }
1717 }
1718 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1719 if (ret == NULL) {
1720 fprintf(stderr, "xmlAddRef: out of memory\n");
1721 return(NULL);
1722 }
1723 table->table[table->nb_refs] = ret;
1724
1725 /*
1726 * fill the structure.
1727 */
1728 ret->value = xmlStrdup(value);
1729 ret->attr = attr;
1730 table->nb_refs++;
1731
1732 return(ret);
1733}
1734
1735/**
1736 * xmlFreeRef:
1737 * @not: A ref
1738 *
1739 * Deallocate the memory used by an ref definition
1740 */
1741void
1742xmlFreeRef(xmlRefPtr ref) {
1743 if (ref == NULL) return;
1744 if (ref->value != NULL)
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001745 xmlFree((xmlChar *) ref->value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001746 memset(ref, -1, sizeof(xmlRef));
1747 xmlFree(ref);
1748}
1749
1750/**
1751 * xmlFreeRefTable:
1752 * @table: An ref table
1753 *
1754 * Deallocate the memory used by an Ref hash table.
1755 */
1756void
1757xmlFreeRefTable(xmlRefTablePtr table) {
1758 int i;
1759
1760 if (table == NULL) return;
1761
1762 for (i = 0;i < table->nb_refs;i++) {
1763 xmlFreeRef(table->table[i]);
1764 }
1765 xmlFree(table->table);
1766 xmlFree(table);
1767}
1768
1769/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001770 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001771 * @doc: the document
1772 * @elem: the element carrying the attribute
1773 * @attr: the attribute
1774 *
1775 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1776 * then this is simple, otherwise we use an heuristic: name Ref (upper
1777 * or lowercase).
1778 *
1779 * Returns 0 or 1 depending on the lookup result
1780 */
1781int
1782xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1783 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1784 return(0);
1785 /*******************
1786 if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1787 ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1788 (attr->name[2] == 0)) return(1);
1789 *******************/
1790 } else {
1791 xmlAttributePtr attrDecl;
1792
1793 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1794 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1795 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1796 attr->name);
1797
1798 if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1799 return(1);
1800 }
1801 return(0);
1802}
1803
1804/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001805 * xmlRemoveRef
1806 * @doc: the document
1807 * @attr: the attribute
1808 *
1809 * Remove the given attribute from the Ref table maintained internally.
1810 *
1811 * Returns -1 if the lookup failed and 0 otherwise
1812 */
1813int
1814xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
1815 xmlRefPtr cur;
1816 xmlRefTablePtr table;
1817 int i;
1818
1819 if (doc == NULL) return(-1);
1820 if (attr == NULL) return(-1);
1821 table = doc->refs;
1822 if (table == NULL)
1823 return(-1);
1824
1825 /*
1826 * Search the Ref list.
1827 */
1828 for (i = 0;i < table->nb_refs;i++) {
1829 cur = table->table[i];
1830 if (cur->attr == attr) {
1831 table->nb_refs--;
1832 memmove(&table->table[i], &table->table[i+1],
1833 (table->nb_refs - i) * sizeof(xmlRefPtr));
1834 return(0);
1835 }
1836 }
1837 return(-1);
1838}
1839
1840/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001841 * xmlGetRef:
1842 * @doc: pointer to the document
1843 * @Ref: the Ref value
1844 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00001845 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001846 *
1847 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1848 */
1849xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001850xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001851 xmlRefPtr cur;
1852 xmlRefTablePtr table;
1853 int i;
1854
1855 if (doc == NULL) {
1856 fprintf(stderr, "xmlGetRef: doc == NULL\n");
1857 return(NULL);
1858 }
1859
1860 if (Ref == NULL) {
1861 fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1862 return(NULL);
1863 }
1864
1865 table = doc->refs;
1866 if (table == NULL)
1867 return(NULL);
1868
1869 /*
1870 * Search the Ref list.
1871 */
1872 for (i = 0;i < table->nb_refs;i++) {
1873 cur = table->table[i];
1874 if (!xmlStrcmp(cur->value, Ref)) {
1875 return(cur->attr);
1876 }
1877 }
1878 return(NULL);
1879}
1880
1881/************************************************************************
1882 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001883 * Routines for validity checking *
1884 * *
1885 ************************************************************************/
1886
1887/**
1888 * xmlGetDtdElementDesc:
1889 * @dtd: a pointer to the DtD to search
1890 * @name: the element name
1891 *
1892 * Search the Dtd for the description of this element
1893 *
1894 * returns the xmlElementPtr if found or NULL
1895 */
1896
1897xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001898xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001899 xmlElementTablePtr table;
1900 xmlElementPtr cur;
1901 int i;
1902
1903 if (dtd == NULL) return(NULL);
1904 if (dtd->elements == NULL) return(NULL);
1905 table = dtd->elements;
1906
1907 for (i = 0;i < table->nb_elements;i++) {
1908 cur = table->table[i];
1909 if (!xmlStrcmp(cur->name, name))
1910 return(cur);
1911 }
1912 return(NULL);
1913}
1914
1915/**
1916 * xmlGetDtdAttrDesc:
1917 * @dtd: a pointer to the DtD to search
1918 * @elem: the element name
1919 * @name: the attribute name
1920 *
1921 * Search the Dtd for the description of this attribute on
1922 * this element.
1923 *
1924 * returns the xmlAttributePtr if found or NULL
1925 */
1926
1927xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001928xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001929 xmlAttributeTablePtr table;
1930 xmlAttributePtr cur;
1931 int i;
1932
1933 if (dtd == NULL) return(NULL);
1934 if (dtd->attributes == NULL) return(NULL);
1935 table = dtd->attributes;
1936
1937 for (i = 0;i < table->nb_attributes;i++) {
1938 cur = table->table[i];
1939 if ((!xmlStrcmp(cur->name, name)) &&
1940 (!xmlStrcmp(cur->elem, elem)))
1941 return(cur);
1942 }
1943 return(NULL);
1944}
1945
1946/**
1947 * xmlGetDtdNotationDesc:
1948 * @dtd: a pointer to the DtD to search
1949 * @name: the notation name
1950 *
1951 * Search the Dtd for the description of this notation
1952 *
1953 * returns the xmlNotationPtr if found or NULL
1954 */
1955
1956xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001957xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001958 xmlNotationTablePtr table;
1959 xmlNotationPtr cur;
1960 int i;
1961
1962 if (dtd == NULL) return(NULL);
1963 if (dtd->notations == NULL) return(NULL);
1964 table = dtd->notations;
1965
1966 for (i = 0;i < table->nb_notations;i++) {
1967 cur = table->table[i];
1968 if (!xmlStrcmp(cur->name, name))
1969 return(cur);
1970 }
1971 return(NULL);
1972}
1973
1974/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001975 * xmlValidateNotationUse:
1976 * @ctxt: the validation context
1977 * @doc: the document
1978 * @notationName: the notation name to check
1979 *
1980 * Validate that the given mame match a notation declaration.
1981 * - [ VC: Notation Declared ]
1982 *
1983 * returns 1 if valid or 0 otherwise
1984 */
1985
1986int
1987xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001988 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001989 xmlNotationPtr notaDecl;
1990 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1991
1992 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1993 if ((notaDecl == NULL) && (doc->extSubset != NULL))
1994 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1995
1996 if (notaDecl == NULL) {
1997 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1998 notationName);
1999 return(0);
2000 }
2001 return(1);
2002}
2003
2004/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002005 * xmlIsMixedElement
2006 * @doc: the document
2007 * @name: the element name
2008 *
2009 * Search in the DtDs whether an element accept Mixed content (or ANY)
2010 * basically if it is supposed to accept text childs
2011 *
2012 * returns 0 if no, 1 if yes, and -1 if no element description is available
2013 */
2014
2015int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002016xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002017 xmlElementPtr elemDecl;
2018
2019 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2020
2021 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2022 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2023 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2024 if (elemDecl == NULL) return(-1);
2025 switch (elemDecl->type) {
2026 case XML_ELEMENT_TYPE_ELEMENT:
2027 return(0);
2028 case XML_ELEMENT_TYPE_EMPTY:
2029 /*
2030 * return 1 for EMPTY since we want VC error to pop up
2031 * on <empty> </empty> for example
2032 */
2033 case XML_ELEMENT_TYPE_ANY:
2034 case XML_ELEMENT_TYPE_MIXED:
2035 return(1);
2036 }
2037 return(1);
2038}
2039
2040/**
2041 * xmlValidateNameValue:
2042 * @value: an Name value
2043 *
2044 * Validate that the given value match Name production
2045 *
2046 * returns 1 if valid or 0 otherwise
2047 */
2048
2049int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002050xmlValidateNameValue(const xmlChar *value) {
2051 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002052
2053 if (value == NULL) return(0);
2054 cur = value;
2055
2056 if (!IS_LETTER(*cur) && (*cur != '_') &&
2057 (*cur != ':')) {
2058 return(0);
2059 }
2060
2061 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2062 (*cur == '.') || (*cur == '-') ||
2063 (*cur == '_') || (*cur == ':') ||
2064 (IS_COMBINING(*cur)) ||
2065 (IS_EXTENDER(*cur)))
2066 cur++;
2067
2068 if (*cur != 0) return(0);
2069
2070 return(1);
2071}
2072
2073/**
2074 * xmlValidateNamesValue:
2075 * @value: an Names value
2076 *
2077 * Validate that the given value match Names production
2078 *
2079 * returns 1 if valid or 0 otherwise
2080 */
2081
2082int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002083xmlValidateNamesValue(const xmlChar *value) {
2084 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002085
2086 if (value == NULL) return(0);
2087 cur = value;
2088
2089 if (!IS_LETTER(*cur) && (*cur != '_') &&
2090 (*cur != ':')) {
2091 return(0);
2092 }
2093
2094 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2095 (*cur == '.') || (*cur == '-') ||
2096 (*cur == '_') || (*cur == ':') ||
2097 (IS_COMBINING(*cur)) ||
2098 (IS_EXTENDER(*cur)))
2099 cur++;
2100
2101 while (IS_BLANK(*cur)) {
2102 while (IS_BLANK(*cur)) cur++;
2103
2104 if (!IS_LETTER(*cur) && (*cur != '_') &&
2105 (*cur != ':')) {
2106 return(0);
2107 }
2108
2109 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2110 (*cur == '.') || (*cur == '-') ||
2111 (*cur == '_') || (*cur == ':') ||
2112 (IS_COMBINING(*cur)) ||
2113 (IS_EXTENDER(*cur)))
2114 cur++;
2115 }
2116
2117 if (*cur != 0) return(0);
2118
2119 return(1);
2120}
2121
2122/**
2123 * xmlValidateNmtokenValue:
2124 * @value: an Mntoken value
2125 *
2126 * Validate that the given value match Nmtoken production
2127 *
2128 * [ VC: Name Token ]
2129 *
2130 * returns 1 if valid or 0 otherwise
2131 */
2132
2133int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002134xmlValidateNmtokenValue(const xmlChar *value) {
2135 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002136
2137 if (value == NULL) return(0);
2138 cur = value;
2139
2140 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2141 (*cur != '.') && (*cur != '-') &&
2142 (*cur != '_') && (*cur != ':') &&
2143 (!IS_COMBINING(*cur)) &&
2144 (!IS_EXTENDER(*cur)))
2145 return(0);
2146
2147 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2148 (*cur == '.') || (*cur == '-') ||
2149 (*cur == '_') || (*cur == ':') ||
2150 (IS_COMBINING(*cur)) ||
2151 (IS_EXTENDER(*cur)))
2152 cur++;
2153
2154 if (*cur != 0) return(0);
2155
2156 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002157}
2158
2159/**
2160 * xmlValidateNmtokensValue:
2161 * @value: an Mntokens value
2162 *
2163 * Validate that the given value match Nmtokens production
2164 *
2165 * [ VC: Name Token ]
2166 *
2167 * returns 1 if valid or 0 otherwise
2168 */
2169
2170int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002171xmlValidateNmtokensValue(const xmlChar *value) {
2172 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002173
2174 if (value == NULL) return(0);
2175 cur = value;
2176
2177 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2178 (*cur != '.') && (*cur != '-') &&
2179 (*cur != '_') && (*cur != ':') &&
2180 (!IS_COMBINING(*cur)) &&
2181 (!IS_EXTENDER(*cur)))
2182 return(0);
2183
2184 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2185 (*cur == '.') || (*cur == '-') ||
2186 (*cur == '_') || (*cur == ':') ||
2187 (IS_COMBINING(*cur)) ||
2188 (IS_EXTENDER(*cur)))
2189 cur++;
2190
2191 while (IS_BLANK(*cur)) {
2192 while (IS_BLANK(*cur)) cur++;
2193
2194 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2195 (*cur != '.') && (*cur != '-') &&
2196 (*cur != '_') && (*cur != ':') &&
2197 (!IS_COMBINING(*cur)) &&
2198 (!IS_EXTENDER(*cur)))
2199 return(0);
2200
2201 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2202 (*cur == '.') || (*cur == '-') ||
2203 (*cur == '_') || (*cur == ':') ||
2204 (IS_COMBINING(*cur)) ||
2205 (IS_EXTENDER(*cur)))
2206 cur++;
2207 }
2208
2209 if (*cur != 0) return(0);
2210
2211 return(1);
2212}
2213
2214/**
2215 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002216 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002217 * @doc: a document instance
2218 * @nota: a notation definition
2219 *
2220 * Try to validate a single notation definition
2221 * basically it does the following checks as described by the
2222 * XML-1.0 recommendation:
2223 * - it seems that no validity constraing exist on notation declarations
2224 * But this function get called anyway ...
2225 *
2226 * returns 1 if valid or 0 otherwise
2227 */
2228
2229int
2230xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2231 xmlNotationPtr nota) {
2232 int ret = 1;
2233
2234 return(ret);
2235}
2236
2237/**
2238 * xmlValidateAttributeValue:
2239 * @type: an attribute type
2240 * @value: an attribute value
2241 *
2242 * Validate that the given attribute value match the proper production
2243 *
2244 * [ VC: ID ]
2245 * Values of type ID must match the Name production....
2246 *
2247 * [ VC: IDREF ]
2248 * Values of type IDREF must match the Name production, and values
2249 * of type IDREFS must match Names ...
2250 *
2251 * [ VC: Entity Name ]
2252 * Values of type ENTITY must match the Name production, values
2253 * of type ENTITIES must match Names ...
2254 *
2255 * [ VC: Name Token ]
2256 * Values of type NMTOKEN must match the Nmtoken production; values
2257 * of type NMTOKENS must match Nmtokens.
2258 *
2259 * returns 1 if valid or 0 otherwise
2260 */
2261
2262int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002263xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002264 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002265 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002266 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002267 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002268 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002269 case XML_ATTRIBUTE_IDREF:
2270 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002271 case XML_ATTRIBUTE_NOTATION:
2272 return(xmlValidateNameValue(value));
2273 case XML_ATTRIBUTE_NMTOKENS:
2274 case XML_ATTRIBUTE_ENUMERATION:
2275 return(xmlValidateNmtokensValue(value));
2276 case XML_ATTRIBUTE_NMTOKEN:
2277 return(xmlValidateNmtokenValue(value));
2278 case XML_ATTRIBUTE_CDATA:
2279 break;
2280 }
2281 return(1);
2282}
2283
2284/**
2285 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002286 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002287 * @doc: a document instance
2288 * @attr: an attribute definition
2289 *
2290 * Try to validate a single attribute definition
2291 * basically it does the following checks as described by the
2292 * XML-1.0 recommendation:
2293 * - [ VC: Attribute Default Legal ]
2294 * - [ VC: Enumeration ]
2295 * - [ VC: ID Attribute Default ]
2296 *
2297 * The ID/IDREF uniqueness and matching are done separately
2298 *
2299 * returns 1 if valid or 0 otherwise
2300 */
2301
2302int
2303xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2304 xmlAttributePtr attr) {
2305 int ret = 1;
2306 int val;
2307 CHECK_DTD;
2308 if(attr == NULL) return(1);
2309
2310 /* Attribute Default Legal */
2311 /* Enumeration */
2312 if (attr->defaultValue != NULL) {
2313 val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2314 if (val == 0) {
2315 VERROR(ctxt->userData,
2316 "Syntax of default value for attribute %s on %s is not valid\n",
2317 attr->name, attr->elem);
2318 }
2319 ret &= val;
2320 }
2321
2322 /* ID Attribute Default */
2323 if ((attr->type == XML_ATTRIBUTE_ID)&&
2324 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2325 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2326 VERROR(ctxt->userData,
2327 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2328 attr->name, attr->elem);
2329 ret = 0;
2330 }
2331
Daniel Veillardb96e6431999-08-29 21:02:19 +00002332 /* One ID per Element Type */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002333 if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2334 int nbId = 0;
2335
2336 /* the trick is taht we parse DtD as their own internal subset */
2337 xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2338 attr->elem);
2339 if (elem != NULL) {
2340 nbId = xmlScanIDAttributeDecl(NULL, elem);
2341 }
2342 if (nbId >= 1)
2343 VERROR(ctxt->userData,
2344 "Element %s has ID attribute defined in the external subset : %s\n",
2345 attr->elem, attr->name);
2346 }
2347
2348 return(ret);
2349}
2350
2351/**
2352 * xmlValidateElementDecl:
2353 * @ctxt: the validation context
2354 * @doc: a document instance
2355 * @elem: an element definition
2356 *
2357 * Try to validate a single element definition
2358 * basically it does the following checks as described by the
2359 * XML-1.0 recommendation:
2360 * - [ VC: One ID per Element Type ]
2361 * - [ VC: No Duplicate Types ]
2362 * - [ VC: Unique Element Type Declaration ]
2363 *
2364 * returns 1 if valid or 0 otherwise
2365 */
2366
2367int
2368xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2369 xmlElementPtr elem) {
2370 int ret = 1;
2371 xmlElementPtr tst;
2372
2373 CHECK_DTD;
2374
2375 if (elem == NULL) return(1);
2376
2377 /* No Duplicate Types */
2378 if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2379 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002380 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002381
2382 cur = elem->content;
2383 while (cur != NULL) {
2384 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2385 if (cur->c1 == NULL) break;
2386 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2387 name = cur->c1->name;
2388 next = cur->c2;
2389 while (next != NULL) {
2390 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2391 if (!xmlStrcmp(next->name, name)) {
2392 VERROR(ctxt->userData,
2393 "Definition of %s has duplicate references of %s\n",
2394 elem->name, name);
2395 ret = 0;
2396 }
2397 break;
2398 }
2399 if (next->c1 == NULL) break;
2400 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2401 if (!xmlStrcmp(next->c1->name, name)) {
2402 VERROR(ctxt->userData,
2403 "Definition of %s has duplicate references of %s\n",
2404 elem->name, name);
2405 ret = 0;
2406 }
2407 next = next->c2;
2408 }
2409 }
2410 cur = cur->c2;
2411 }
2412 }
2413
2414 /* VC: Unique Element Type Declaration */
2415 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2416 if ((tst != NULL ) && (tst != elem)) {
2417 VERROR(ctxt->userData, "Redefinition of element %s\n",
2418 elem->name);
2419 ret = 0;
2420 }
2421 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2422 if ((tst != NULL ) && (tst != elem)) {
2423 VERROR(ctxt->userData, "Redefinition of element %s\n",
2424 elem->name);
2425 ret = 0;
2426 }
2427
2428 /* One ID per Element Type */
2429 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2430 ret = 0;
2431 }
2432 return(ret);
2433}
2434
2435/**
2436 * xmlValidateOneAttribute:
2437 * @ctxt: the validation context
2438 * @doc: a document instance
2439 * @elem: an element instance
2440 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002441 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002442 *
2443 * Try to validate a single attribute for an element
2444 * basically it * does the following checks as described by the
2445 * XML-1.0 recommendation:
2446 * - [ VC: Attribute Value Type ]
2447 * - [ VC: Fixed Attribute Default ]
2448 * - [ VC: Entity Name ]
2449 * - [ VC: Name Token ]
2450 * - [ VC: ID ]
2451 * - [ VC: IDREF ]
2452 * - [ VC: Entity Name ]
2453 * - [ VC: Notation Attributes ]
2454 *
2455 * The ID/IDREF uniqueness and matching are done separately
2456 *
2457 * returns 1 if valid or 0 otherwise
2458 */
2459
2460int
2461xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002462 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002463 /* xmlElementPtr elemDecl; */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002464 xmlAttributePtr attrDecl;
2465 int val;
2466 int ret = 1;
2467
2468 CHECK_DTD;
2469 if ((elem == NULL) || (elem->name == NULL)) return(0);
2470 if ((attr == NULL) || (attr->name == NULL)) return(0);
2471
2472 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2473 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2474 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2475
2476
2477 /* Validity Constraint: Attribute Value Type */
2478 if (attrDecl == NULL) {
2479 VERROR(ctxt->userData,
2480 "No declaration for attribute %s on element %s\n",
2481 attr->name, elem->name);
2482 return(0);
2483 }
2484 val = xmlValidateAttributeValue(attrDecl->type, value);
2485 if (val == 0) {
2486 VERROR(ctxt->userData,
2487 "Syntax of value for attribute %s on %s is not valid\n",
2488 attr->name, elem->name);
2489 ret = 0;
2490 }
2491
Daniel Veillardb96e6431999-08-29 21:02:19 +00002492 /* Validity Constraint: ID uniqueness */
2493 if (attrDecl->type == XML_ATTRIBUTE_ID) {
2494 xmlAddID(ctxt, doc, value, attr);
2495 }
2496
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002497 if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2498 xmlAddRef(ctxt, doc, value, attr);
2499 }
2500
Daniel Veillardb05deb71999-08-10 19:04:08 +00002501 /* Validity Constraint: Notation Attributes */
2502 if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2503 xmlEnumerationPtr tree = attrDecl->tree;
2504 xmlNotationPtr nota;
2505
2506 /* First check that the given NOTATION was declared */
2507 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2508 if (nota == NULL)
2509 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2510
2511 if (nota == NULL) {
2512 VERROR(ctxt->userData,
2513 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2514 value, attr->name, elem->name);
2515 ret = 0;
2516 }
2517
2518 /* Second, verify that it's among the list */
2519 while (tree != NULL) {
2520 if (!xmlStrcmp(tree->name, value)) break;
2521 tree = tree->next;
2522 }
2523 if (tree == NULL) {
2524 VERROR(ctxt->userData,
2525 "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2526 value, attr->name, elem->name);
2527 ret = 0;
2528 }
2529 }
2530
2531 /* Validity Constraint: Enumeration */
2532 if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2533 xmlEnumerationPtr tree = attrDecl->tree;
2534 while (tree != NULL) {
2535 if (!xmlStrcmp(tree->name, value)) break;
2536 tree = tree->next;
2537 }
2538 if (tree == NULL) {
2539 VERROR(ctxt->userData,
2540 "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2541 value, attr->name, elem->name);
2542 ret = 0;
2543 }
2544 }
2545
2546 /* Fixed Attribute Default */
2547 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2548 (xmlStrcmp(attrDecl->defaultValue, value))) {
2549 VERROR(ctxt->userData,
2550 "Value for attribute %s on %s must be \"%s\"\n",
2551 attr->name, elem->name, attrDecl->defaultValue);
2552 ret = 0;
2553 }
2554
Daniel Veillardb96e6431999-08-29 21:02:19 +00002555 /********
Daniel Veillardb05deb71999-08-10 19:04:08 +00002556 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2557 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2558 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2559 if (elemDecl == NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002560 return(0);
2561 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002562 ********/
Daniel Veillardb05deb71999-08-10 19:04:08 +00002563 return(ret);
2564}
2565
2566int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2567 xmlElementContentPtr cont);
2568
2569/**
2570 * xmlValidateElementTypeExpr:
2571 * @ctxt: the validation context
2572 * @child: pointer to the child list
2573 * @cont: pointer to the content declaration
2574 *
2575 * Try to validate the content of an element of type element
2576 * but don't handle the occurence factor
2577 *
2578 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2579 * also update child value in-situ.
2580 */
2581
2582int
2583xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2584 xmlElementContentPtr cont) {
2585 xmlNodePtr cur;
2586 int ret = 1;
2587
2588 if (cont == NULL) return(-1);
2589 while (*child != NULL) {
2590 if ((*child)->type == XML_PI_NODE) {
2591 *child = (*child)->next;
2592 continue;
2593 }
2594 if ((*child)->type == XML_COMMENT_NODE) {
2595 *child = (*child)->next;
2596 continue;
2597 }
2598 else if ((*child)->type != XML_ELEMENT_NODE) {
2599 return(-1);
2600 }
2601 break;
2602 }
2603 switch (cont->type) {
2604 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00002605 if (*child == NULL) return(0);
2606 if ((*child)->type == XML_TEXT_NODE) return(1);
2607 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002608 case XML_ELEMENT_CONTENT_ELEMENT:
2609 if (*child == NULL) return(0);
2610 ret = (!xmlStrcmp((*child)->name, cont->name));
2611 if (ret == 1)
2612 *child = (*child)->next;
2613 return(ret);
2614 case XML_ELEMENT_CONTENT_OR:
2615 cur = *child;
2616 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2617 if (ret == -1) return(-1);
2618 if (ret == 1) {
2619 return(1);
2620 }
2621 /* rollback and retry the other path */
2622 *child = cur;
2623 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2624 if (ret == -1) return(-1);
2625 if (ret == 0) {
2626 *child = cur;
2627 return(0);
2628 }
2629 return(1);
2630 case XML_ELEMENT_CONTENT_SEQ:
2631 cur = *child;
2632 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2633 if (ret == -1) return(-1);
2634 if (ret == 0) {
2635 *child = cur;
2636 return(0);
2637 }
2638 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2639 if (ret == -1) return(-1);
2640 if (ret == 0) {
2641 *child = cur;
2642 return(0);
2643 }
2644 return(1);
2645 }
2646 return(ret);
2647}
2648
2649/**
2650 * xmlValidateElementTypeElement:
2651 * @ctxt: the validation context
2652 * @child: pointer to the child list
2653 * @cont: pointer to the content declaration
2654 *
2655 * Try to validate the content of an element of type element
2656 * yeah, Yet Another Regexp Implementation, and recursive
2657 *
2658 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2659 * also update child and content values in-situ.
2660 */
2661
2662int
2663xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2664 xmlElementContentPtr cont) {
2665 xmlNodePtr cur;
2666 int ret = 1;
2667
2668 if (cont == NULL) return(-1);
2669 while (*child != NULL) {
2670 if ((*child)->type == XML_PI_NODE) {
2671 *child = (*child)->next;
2672 continue;
2673 }
2674 if ((*child)->type == XML_COMMENT_NODE) {
2675 *child = (*child)->next;
2676 continue;
2677 }
2678 else if ((*child)->type != XML_ELEMENT_NODE) {
2679 return(-1);
2680 }
2681 break;
2682 }
2683 cur = *child;
2684 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2685 if (ret == -1) return(-1);
2686 switch (cont->ocur) {
2687 case XML_ELEMENT_CONTENT_ONCE:
2688 if (ret == 1) {
2689 return(1);
2690 }
2691 *child = cur;
2692 return(0);
2693 case XML_ELEMENT_CONTENT_OPT:
2694 if (ret == 0) {
2695 *child = cur;
2696 return(1);
2697 }
2698 break;
2699 case XML_ELEMENT_CONTENT_MULT:
2700 if (ret == 0) {
2701 *child = cur;
2702 break;
2703 }
2704 /* no break on purpose */
2705 case XML_ELEMENT_CONTENT_PLUS:
2706 if (ret == 0) {
2707 *child = cur;
2708 return(0);
2709 }
2710 do {
2711 cur = *child;
2712 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2713 } while (ret == 1);
2714 if (ret == -1) return(-1);
2715 *child = cur;
2716 break;
2717 }
2718 while (*child != NULL) {
2719 if ((*child)->type == XML_PI_NODE) {
2720 *child = (*child)->next;
2721 continue;
2722 }
2723 if ((*child)->type == XML_COMMENT_NODE) {
2724 *child = (*child)->next;
2725 continue;
2726 }
2727 else if ((*child)->type != XML_ELEMENT_NODE) {
2728 return(-1);
2729 }
2730 break;
2731 }
2732 return(1);
2733}
2734
2735/**
2736 * xmlSprintfElementChilds:
2737 * @buf: an output buffer
2738 * @content: An element
2739 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2740 *
2741 * This will dump the list of childs to the buffer
2742 * Intended just for the debug routine
2743 */
2744void
2745xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2746 xmlNodePtr cur;
2747
2748 if (node == NULL) return;
2749 if (glob) strcat(buf, "(");
2750 cur = node->childs;
2751 while (cur != NULL) {
2752 switch (cur->type) {
2753 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002754 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002755 if (cur->next != NULL)
2756 strcat(buf, " ");
2757 break;
2758 case XML_TEXT_NODE:
2759 case XML_CDATA_SECTION_NODE:
2760 case XML_ENTITY_REF_NODE:
2761 strcat(buf, "CDATA");
2762 if (cur->next != NULL)
2763 strcat(buf, " ");
2764 break;
2765 case XML_ATTRIBUTE_NODE:
2766 case XML_DOCUMENT_NODE:
Daniel Veillard7c1206f1999-10-14 09:10:25 +00002767 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002768 case XML_DOCUMENT_TYPE_NODE:
2769 case XML_DOCUMENT_FRAG_NODE:
2770 case XML_NOTATION_NODE:
2771 strcat(buf, "???");
2772 if (cur->next != NULL)
2773 strcat(buf, " ");
2774 break;
2775 case XML_ENTITY_NODE:
2776 case XML_PI_NODE:
2777 case XML_COMMENT_NODE:
2778 break;
2779 }
2780 cur = cur->next;
2781 }
2782 if (glob) strcat(buf, ")");
2783}
2784
2785
2786/**
2787 * xmlValidateOneElement:
2788 * @ctxt: the validation context
2789 * @doc: a document instance
2790 * @elem: an element instance
2791 *
2792 * Try to validate a single element and it's attributes,
2793 * basically it does the following checks as described by the
2794 * XML-1.0 recommendation:
2795 * - [ VC: Element Valid ]
2796 * - [ VC: Required Attribute ]
2797 * Then call xmlValidateOneAttribute() for each attribute present.
2798 *
2799 * The ID/IDREF checkings are done separately
2800 *
2801 * returns 1 if valid or 0 otherwise
2802 */
2803
2804int
2805xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2806 xmlNodePtr elem) {
2807 xmlElementPtr elemDecl;
2808 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002809 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002810 xmlNodePtr child;
2811 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002812 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002813
2814 CHECK_DTD;
2815
Daniel Veillard944b5ff1999-12-15 19:08:24 +00002816 if (elem == NULL) return(0);
2817 if (elem->type == XML_TEXT_NODE) {
2818 }
2819 switch (elem->type) {
2820 case XML_ATTRIBUTE_NODE:
2821 VERROR(ctxt->userData,
2822 "Attribute element not expected here\n");
2823 return(0);
2824 case XML_TEXT_NODE:
2825 if (elem->childs != NULL) {
2826 VERROR(ctxt->userData, "Text element has childs !\n");
2827 return(0);
2828 }
2829 if (elem->properties != NULL) {
2830 VERROR(ctxt->userData, "Text element has attributes !\n");
2831 return(0);
2832 }
2833 if (elem->ns != NULL) {
2834 VERROR(ctxt->userData, "Text element has namespace !\n");
2835 return(0);
2836 }
2837 if (elem->ns != NULL) {
2838 VERROR(ctxt->userData,
2839 "Text element carries namespace definitions !\n");
2840 return(0);
2841 }
2842 if (elem->content == NULL) {
2843 VERROR(ctxt->userData,
2844 "Text element has no content !\n");
2845 return(0);
2846 }
2847 return(1);
2848 case XML_CDATA_SECTION_NODE:
2849 case XML_ENTITY_REF_NODE:
2850 case XML_PI_NODE:
2851 case XML_COMMENT_NODE:
2852 return(1);
2853 case XML_ENTITY_NODE:
2854 VERROR(ctxt->userData,
2855 "Entity element not expected here\n");
2856 return(0);
2857 case XML_NOTATION_NODE:
2858 VERROR(ctxt->userData,
2859 "Notation element not expected here\n");
2860 return(0);
2861 case XML_DOCUMENT_NODE:
2862 case XML_DOCUMENT_TYPE_NODE:
2863 case XML_DOCUMENT_FRAG_NODE:
2864 VERROR(ctxt->userData,
2865 "Document element not expected here\n");
2866 return(0);
2867 case XML_HTML_DOCUMENT_NODE:
2868 VERROR(ctxt->userData,
2869 "\n");
2870 return(0);
2871 case XML_ELEMENT_NODE:
2872 break;
2873 default:
2874 VERROR(ctxt->userData,
2875 "unknown element type %d\n", elem->type);
2876 return(0);
2877 }
2878 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002879
2880 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2881 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2882 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2883 if (elemDecl == NULL) {
2884 VERROR(ctxt->userData, "No declaration for element %s\n",
2885 elem->name);
2886 return(0);
2887 }
2888
2889 /* Check taht the element content matches the definition */
2890 switch (elemDecl->type) {
2891 case XML_ELEMENT_TYPE_EMPTY:
2892 if (elem->childs != NULL) {
2893 VERROR(ctxt->userData,
2894 "Element %s was declared EMPTY this one has content\n",
2895 elem->name);
2896 ret = 0;
2897 }
2898 break;
2899 case XML_ELEMENT_TYPE_ANY:
2900 /* I don't think anything is required then */
2901 break;
2902 case XML_ELEMENT_TYPE_MIXED:
2903 /* Hum, this start to get messy */
2904 child = elem->childs;
2905 while (child != NULL) {
2906 if (child->type == XML_ELEMENT_NODE) {
2907 name = child->name;
2908 cont = elemDecl->content;
2909 while (cont != NULL) {
2910 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2911 if (!xmlStrcmp(cont->name, name)) break;
2912 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2913 (cont->c1 != NULL) &&
2914 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2915 if (!xmlStrcmp(cont->c1->name, name)) break;
2916 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2917 (cont->c1 == NULL) ||
2918 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2919 /* Internal error !!! */
2920 fprintf(stderr, "Internal: MIXED struct bad\n");
2921 break;
2922 }
2923 cont = cont->c2;
2924 }
2925 if (cont == NULL) {
2926 VERROR(ctxt->userData,
2927 "Element %s is not declared in %s list of possible childs\n",
2928 name, elem->name);
2929 ret = 0;
2930 }
2931 }
2932 child = child->next;
2933 }
2934 break;
2935 case XML_ELEMENT_TYPE_ELEMENT:
2936 child = elem->childs;
2937 cont = elemDecl->content;
2938 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
2939 if ((ret == 0) || (child != NULL)) {
2940 char expr[1000];
2941 char list[2000];
2942
2943 expr[0] = 0;
2944 xmlSprintfElementContent(expr, cont, 1);
2945 list[0] = 0;
2946 xmlSprintfElementChilds(list, elem, 1);
2947
2948 VERROR(ctxt->userData,
2949 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2950 elem->name, expr, list);
2951 ret = 0;
2952 }
2953 break;
2954 }
2955
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002956 /* [ VC: Required Attribute ] */
2957 attr = elemDecl->attributes;
2958 while (attr != NULL) {
2959 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
2960 xmlAttrPtr attrib;
2961 int qualified = -1;
2962
2963 attrib = elem->properties;
2964 while (attrib != NULL) {
2965 if (!xmlStrcmp(attrib->name, attr->name)) {
2966 if (attr->prefix != NULL) {
2967 xmlNsPtr nameSpace = attrib->ns;
2968
2969 if (nameSpace == NULL)
2970 nameSpace = elem->ns;
2971 /*
2972 * qualified names handling is problematic, having a
2973 * different prefix should be possible but DTDs don't
2974 * allow to define the URI instead of the prefix :-(
2975 */
2976 if (nameSpace == NULL) {
2977 if (qualified < 0)
2978 qualified = 0;
2979 } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
2980 if (qualified < 1)
2981 qualified = 1;
2982 } else
2983 goto found;
2984 } else {
2985 /*
2986 * We should allow applications to define namespaces
2987 * for their application even if the DTD doesn't
2988 * carry one, otherwise, basically we would always
2989 * break.
2990 */
2991 goto found;
2992 }
2993 }
2994 attrib = attrib->next;
2995 }
2996 if (qualified == -1) {
2997 if (attr->prefix == NULL) {
2998 VERROR(ctxt->userData,
2999 "Element %s doesn't carry attribute %s\n",
3000 elem->name, attr->name);
3001 } else {
3002 VERROR(ctxt->userData,
3003 "Element %s doesn't carry attribute %s:%s\n",
3004 elem->name, attr->prefix,attr->name);
3005 }
3006 } else if (qualified == 0) {
3007 VWARNING(ctxt->userData,
3008 "Element %s required attribute %s:%s has no prefix\n",
3009 elem->name, attr->prefix,attr->name);
3010 } else if (qualified == 1) {
3011 VWARNING(ctxt->userData,
3012 "Element %s required attribute %s:%s has different prefix\n",
3013 elem->name, attr->prefix,attr->name);
3014 }
3015 }
3016found:
3017 attr = attr->next;
3018 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003019 return(ret);
3020}
3021
3022/**
3023 * xmlValidateRoot:
3024 * @ctxt: the validation context
3025 * @doc: a document instance
3026 *
3027 * Try to validate a the root element
3028 * basically it does the following check as described by the
3029 * XML-1.0 recommendation:
3030 * - [ VC: Root Element Type ]
3031 * it doesn't try to recurse or apply other check to the element
3032 *
3033 * returns 1 if valid or 0 otherwise
3034 */
3035
3036int
3037xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003038 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003039 if (doc == NULL) return(0);
3040
3041 if ((doc->intSubset == NULL) ||
3042 (doc->intSubset->name == NULL)) {
3043 VERROR(ctxt->userData, "Not valid: no DtD found\n");
3044 return(0);
3045 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003046 root = xmlDocGetRootElement(doc);
3047 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003048 VERROR(ctxt->userData, "Not valid: no root element\n");
3049 return(0);
3050 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003051 if (xmlStrcmp(doc->intSubset->name, root->name)) {
Daniel Veillardda07c342000-01-25 18:31:22 +00003052 if ((xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) ||
3053 (xmlStrcmp(root->name, BAD_CAST "html"))) {
3054 VERROR(ctxt->userData,
3055 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3056 root->name, doc->intSubset->name);
3057 return(0);
3058 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003059 }
3060 return(1);
3061}
3062
3063
3064/**
3065 * xmlValidateElement:
3066 * @ctxt: the validation context
3067 * @doc: a document instance
3068 * @elem: an element instance
3069 *
3070 * Try to validate the subtree under an element
3071 *
3072 * returns 1 if valid or 0 otherwise
3073 */
3074
3075int
3076xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003077 xmlNodePtr child;
3078 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003079 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003080 int ret = 1;
3081
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003082 if (elem == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003083 CHECK_DTD;
3084
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003085 ret &= xmlValidateOneElement(ctxt, doc, elem);
3086 attr = elem->properties;
3087 while(attr != NULL) {
3088 value = xmlNodeListGetString(doc, attr->val, 0);
3089 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3090 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003091 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003092 attr= attr->next;
3093 }
3094 child = elem->childs;
3095 while (child != NULL) {
3096 ret &= xmlValidateElement(ctxt, doc, child);
3097 child = child->next;
3098 }
3099
3100 return(ret);
3101}
3102
3103/**
3104 * xmlValidateDocumentFinal:
3105 * @ctxt: the validation context
3106 * @doc: a document instance
3107 *
3108 * Does the final step for the document validation once all the
3109 * incremental validation steps have been completed
3110 *
3111 * basically it does the following checks described by the XML Rec
3112 *
3113 *
3114 * returns 1 if valid or 0 otherwise
3115 */
3116
3117int
3118xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3119 int ret = 1, i;
3120 xmlRefTablePtr table;
3121 xmlAttrPtr id;
3122
3123 if (doc == NULL) {
3124 fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3125 return(0);
3126 }
3127
3128 /*
3129 * Get the refs table
3130 */
3131 table = doc->refs;
3132 if (table != NULL) {
3133 for (i = 0; i < table->nb_refs; i++) {
3134 id = xmlGetID(doc, table->table[i]->value);
3135 if (id == NULL) {
3136 VERROR(ctxt->userData,
3137 "IDREF attribute %s reference an unknown ID '%s'\n",
3138 table->table[i]->attr->name, table->table[i]->value);
3139 ret = 0;
3140 }
3141 }
3142 }
3143 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003144}
3145
3146/**
3147 * xmlValidateDtd:
3148 * @ctxt: the validation context
3149 * @doc: a document instance
3150 * @dtd: a dtd instance
3151 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003152 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003153 *
3154 * basically it does check all the definitions in the DtD.
3155 *
3156 * returns 1 if valid or 0 otherwise
3157 */
3158
3159int
3160xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003161 int ret;
3162 xmlDtdPtr oldExt;
3163 xmlNodePtr root;
3164
3165 if (dtd == NULL) return(0);
3166 if (doc == NULL) return(0);
3167 oldExt = doc->extSubset;
3168 doc->extSubset = dtd;
3169 ret = xmlValidateRoot(ctxt, doc);
3170 if (ret == 0) {
3171 doc->extSubset = oldExt;
3172 return(ret);
3173 }
3174 root = xmlDocGetRootElement(doc);
3175 ret = xmlValidateElement(ctxt, doc, root);
3176 ret &= xmlValidateDocumentFinal(ctxt, doc);
3177 doc->extSubset = oldExt;
3178 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003179}
3180
3181/**
3182 * xmlValidateDocument:
3183 * @ctxt: the validation context
3184 * @doc: a document instance
3185 *
3186 * Try to validate the document instance
3187 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003188 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00003189 * i.e. validates the internal and external subset (if present)
3190 * and validate the document tree.
3191 *
3192 * returns 1 if valid or 0 otherwise
3193 */
3194
3195int
3196xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003197 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003198 xmlNodePtr root;
3199
3200 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3201 return(0);
3202 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3203 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3204 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3205 doc->intSubset->SystemID);
3206 if (doc->extSubset == NULL) {
3207 if (doc->intSubset->SystemID != NULL) {
3208 VERROR(ctxt->userData,
3209 "Could not load the external subset '%s'\n",
3210 doc->intSubset->SystemID);
3211 } else {
3212 VERROR(ctxt->userData,
3213 "Could not load the external subset '%s'\n",
3214 doc->intSubset->ExternalID);
3215 }
3216 return(0);
3217 }
3218 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003219
Daniel Veillardb05deb71999-08-10 19:04:08 +00003220 if (!xmlValidateRoot(ctxt, doc)) return(0);
3221
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003222 root = xmlDocGetRootElement(doc);
3223 ret = xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003224 ret &= xmlValidateDocumentFinal(ctxt, doc);
3225 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003226}
3227
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003228
3229/************************************************************************
3230 * *
3231 * Routines for dynamic validation editing *
3232 * *
3233 ************************************************************************/
3234
3235/**
3236 * xmlValidGetPotentialChildren:
3237 * @ctree: an element content tree
3238 * @list: an array to store the list of child names
3239 * @len: a pointer to the number of element in the list
3240 * @max: the size of the array
3241 *
3242 * Build/extend a list of potential children allowed by the content tree
3243 *
3244 * returns the number of element in the list, or -1 in case of error.
3245 */
3246
3247int
3248xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3249 int *len, int max) {
3250 int i;
3251
3252 if ((ctree == NULL) || (list == NULL) || (len == NULL))
3253 return(-1);
3254 if (*len >= max) return(*len);
3255
3256 switch (ctree->type) {
3257 case XML_ELEMENT_CONTENT_PCDATA:
3258 for (i = 0; i < *len;i++)
Daniel Veillarda819dac1999-11-24 18:04:22 +00003259 if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
3260 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003261 break;
3262 case XML_ELEMENT_CONTENT_ELEMENT:
3263 for (i = 0; i < *len;i++)
3264 if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3265 list[(*len)++] = ctree->name;
3266 break;
3267 case XML_ELEMENT_CONTENT_SEQ:
3268 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3269 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3270 break;
3271 case XML_ELEMENT_CONTENT_OR:
3272 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3273 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3274 break;
3275 }
3276
3277 return(*len);
3278}
3279
3280/**
3281 * xmlValidGetValidElements:
3282 * @prev: an element to insert after
3283 * @next: an element to insert next
3284 * @list: an array to store the list of child names
3285 * @max: the size of the array
3286 *
3287 * This function returns the list of authorized children to insert
3288 * within an existing tree while respecting the validity constraints
3289 * forced by the Dtd. The insertion point is defined using @prev and
3290 * @next in the following ways:
3291 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3292 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3293 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3294 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3295 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
3296 *
3297 * pointers to the element names are inserted at the beginning of the array
3298 * and do not need to be freed.
3299 *
3300 * returns the number of element in the list, or -1 in case of error. If
3301 * the function returns the value @max the caller is invited to grow the
3302 * receiving array and retry.
3303 */
3304
3305int
3306xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3307 int max) {
3308 int nb_valid_elements = 0;
3309 const xmlChar *elements[256];
3310 int nb_elements = 0, i;
3311
3312 xmlNode *ref_node;
3313 xmlNode *parent;
3314 xmlNode *test_node;
3315
3316 xmlNode *prev_next;
3317 xmlNode *next_prev;
3318 xmlNode *parent_childs;
3319 xmlNode *parent_last;
3320
3321 xmlElement *element_desc;
3322
3323 if (prev == NULL && next == NULL)
3324 return(-1);
3325
3326 if (list == NULL) return(-1);
3327 if (max <= 0) return(-1);
3328
3329 nb_valid_elements = 0;
3330 ref_node = prev ? prev : next;
3331 parent = ref_node->parent;
3332
3333 /*
3334 * Retrieves the parent element declaration
3335 */
3336 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3337 parent->name);
3338 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3339 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3340 parent->name);
3341 if (element_desc == NULL) return(-1);
3342
3343 /*
3344 * Do a backup of the current tree structure
3345 */
3346 prev_next = prev ? prev->next : NULL;
3347 next_prev = next ? next->prev : NULL;
3348 parent_childs = parent->childs;
3349 parent_last = parent->last;
3350
3351 /*
3352 * Creates a dummy node and insert it into the tree
3353 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003354 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003355 test_node->doc = ref_node->doc;
3356 test_node->parent = parent;
3357 test_node->prev = prev;
3358 test_node->next = next;
3359
3360 if (prev) prev->next = test_node;
3361 else parent->childs = test_node;
3362
3363 if (next) next->prev = test_node;
3364 else parent->last = test_node;
3365
3366 /*
3367 * Insert each potential child node and check if the parent is
3368 * still valid
3369 */
3370 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3371 elements, &nb_elements, 256);
3372
3373 for (i = 0;i < nb_elements;i++) {
3374 test_node->name = elements[i];
3375 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3376 int j;
3377
3378 for (j = 0; j < nb_valid_elements;j++)
3379 if (!xmlStrcmp(elements[i], list[j])) break;
3380 list[nb_valid_elements++] = elements[i];
3381 if (nb_valid_elements >= max) break;
3382 }
3383 }
3384
3385 /*
3386 * Restore the tree structure
3387 */
3388 if (prev) prev->next = prev_next;
3389 if (next) next->prev = next_prev;
3390 parent->childs = parent_childs;
3391 parent->last = parent_last;
3392
3393 return(nb_valid_elements);
3394}