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