Coverage Report

Created: 2024-01-18 09:16

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