Coverage Report

Created: 2023-06-07 06:14

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