~ubuntu-branches/ubuntu/utopic/libxml2/utopic

« back to all changes in this revision

Viewing changes to .pc/0018-Fix-pointer-dereferenced-before-null-check.patch/valid.c

  • Committer: Package Import Robot
  • Author(s): Aron Xu, Christian Svensson, Daniel Schepler, Helmut Grohne, Adam Conrad, Matthias Klose, Aron Xu
  • Date: 2014-07-09 05:40:15 UTC
  • mto: This revision was merged to the branch mainline in revision 75.
  • Revision ID: package-import@ubuntu.com-20140709054015-rdnfjxrf3zvmw6l7
[ Christian Svensson ]
* Do not build-depend on readline (Closes: #742350)

[ Daniel Schepler ]
* Patch to bootstrap without python (Closes: #738080)

[ Helmut Grohne ]
* Drop unneeded B-D on perl and binutils (Closes: #753005)

[ Adam Conrad ]
* Actually run dh_autoreconf, which the old/new mixed rules file misses.

[ Matthias Klose ]
* Add patch to fix python multiarch issue
* Allow the package to cross-build by tweaking B-Ds on python
* Set PYTHON_LIBS for cross builds

[ Aron Xu ]
* Use correct $CC
* Configure udeb without python
* New round of cherry-picking upstream fixes
  - Includes fixes for CVE-2014-0191 (Closes: #747309).
* Call prename with -vf
* Require python-all-dev (>= 2.7.5-5~)
* Bump std-ver: 3.9.4 -> 3.9.5, no change

Show diffs side-by-side

added added

removed removed

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