Coverage Report

Created: 2025-08-04 07:15

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