Coverage Report

Created: 2023-12-14 16:40

/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
2.03k
{
99
2.03k
    xmlGenericErrorFunc channel = NULL;
100
2.03k
    xmlParserCtxtPtr pctxt = NULL;
101
2.03k
    void *data = NULL;
102
103
2.03k
    if (ctxt != NULL) {
104
1.75k
        channel = ctxt->error;
105
1.75k
        data = ctxt->userData;
106
  /* Look up flag to detect if it is part of a parsing
107
     context */
108
1.75k
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
109
1.75k
      long delta = (char *) ctxt - (char *) ctxt->userData;
110
1.75k
      if ((delta > 0) && (delta < 250))
111
1.75k
    pctxt = ctxt->userData;
112
1.75k
  }
113
1.75k
    }
114
2.03k
    if (extra)
115
281
        __xmlRaiseError(NULL, channel, data,
116
281
                        pctxt, NULL, XML_FROM_VALID, error,
117
281
                        XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
118
281
                        msg, extra);
119
1.75k
    else
120
1.75k
        __xmlRaiseError(NULL, channel, data,
121
1.75k
                        pctxt, NULL, XML_FROM_VALID, error,
122
1.75k
                        XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
123
1.75k
                        "%s", msg);
124
2.03k
}
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
2.76M
{
144
2.76M
    xmlStructuredErrorFunc schannel = NULL;
145
2.76M
    xmlGenericErrorFunc channel = NULL;
146
2.76M
    xmlParserCtxtPtr pctxt = NULL;
147
2.76M
    void *data = NULL;
148
149
2.76M
    if (ctxt != NULL) {
150
2.76M
        channel = ctxt->error;
151
2.76M
        data = ctxt->userData;
152
  /* Look up flag to detect if it is part of a parsing
153
     context */
154
2.76M
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
155
2.75M
      long delta = (char *) ctxt - (char *) ctxt->userData;
156
2.75M
      if ((delta > 0) && (delta < 250))
157
2.70M
    pctxt = ctxt->userData;
158
2.75M
  }
159
2.76M
    }
160
2.76M
    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
161
2.76M
                    XML_ERR_ERROR, NULL, 0,
162
2.76M
                    (const char *) str1,
163
2.76M
                    (const char *) str2,
164
2.76M
                    (const char *) str3, 0, 0, msg, str1, str2, str3);
165
2.76M
}
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.05k
{
186
2.05k
    xmlStructuredErrorFunc schannel = NULL;
187
2.05k
    xmlGenericErrorFunc channel = NULL;
188
2.05k
    xmlParserCtxtPtr pctxt = NULL;
189
2.05k
    void *data = NULL;
190
191
2.05k
    if (ctxt != NULL) {
192
2.05k
        channel = ctxt->error;
193
2.05k
        data = ctxt->userData;
194
  /* Look up flag to detect if it is part of a parsing
195
     context */
196
2.05k
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
197
286
      long delta = (char *) ctxt - (char *) ctxt->userData;
198
286
      if ((delta > 0) && (delta < 250))
199
286
    pctxt = ctxt->userData;
200
286
  }
201
2.05k
    }
202
2.05k
    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
203
2.05k
                    XML_ERR_ERROR, NULL, 0,
204
2.05k
                    (const char *) str1,
205
2.05k
                    (const char *) str3,
206
2.05k
                    NULL, int2, 0, msg, str1, int2, str3);
207
2.05k
}
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
136k
{
226
136k
    xmlStructuredErrorFunc schannel = NULL;
227
136k
    xmlGenericErrorFunc channel = NULL;
228
136k
    xmlParserCtxtPtr pctxt = NULL;
229
136k
    void *data = NULL;
230
231
136k
    if (ctxt != NULL) {
232
136k
        channel = ctxt->warning;
233
136k
        data = ctxt->userData;
234
  /* Look up flag to detect if it is part of a parsing
235
     context */
236
136k
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
237
136k
      long delta = (char *) ctxt - (char *) ctxt->userData;
238
136k
      if ((delta > 0) && (delta < 250))
239
136k
    pctxt = ctxt->userData;
240
136k
  }
241
136k
    }
242
136k
    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
243
136k
                    XML_ERR_WARNING, NULL, 0,
244
136k
                    (const char *) str1,
245
136k
                    (const char *) str2,
246
136k
                    (const char *) str3, 0, 0, msg, str1, str2, str3);
247
136k
}
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
535k
vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
270
535k
    if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
271
13.9k
  ctxt->vstateMax = 10;
272
13.9k
  ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
273
13.9k
                  sizeof(ctxt->vstateTab[0]));
274
13.9k
        if (ctxt->vstateTab == NULL) {
275
0
      xmlVErrMemory(ctxt, "malloc failed");
276
0
      return(-1);
277
0
  }
278
13.9k
    }
279
280
535k
    if (ctxt->vstateNr >= ctxt->vstateMax) {
281
291
        xmlValidState *tmp;
282
283
291
  tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
284
291
               2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
285
291
        if (tmp == NULL) {
286
0
      xmlVErrMemory(ctxt, "realloc failed");
287
0
      return(-1);
288
0
  }
289
291
  ctxt->vstateMax *= 2;
290
291
  ctxt->vstateTab = tmp;
291
291
    }
292
535k
    ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
293
535k
    ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
294
535k
    ctxt->vstateTab[ctxt->vstateNr].node = node;
295
535k
    if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
296
76.8k
  if (elemDecl->contModel == NULL)
297
21.2k
      xmlValidBuildContentModel(ctxt, elemDecl);
298
76.8k
  if (elemDecl->contModel != NULL) {
299
76.8k
      ctxt->vstateTab[ctxt->vstateNr].exec =
300
76.8k
    xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
301
76.8k
  } 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
76.8k
    }
309
535k
    return(ctxt->vstateNr++);
310
535k
}
311
312
static int
313
535k
vstateVPop(xmlValidCtxtPtr ctxt) {
314
535k
    xmlElementPtr elemDecl;
315
316
535k
    if (ctxt->vstateNr < 1) return(-1);
317
535k
    ctxt->vstateNr--;
318
535k
    elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
319
535k
    ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
320
535k
    ctxt->vstateTab[ctxt->vstateNr].node = NULL;
321
535k
    if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
322
76.8k
  xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
323
76.8k
    }
324
535k
    ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
325
535k
    if (ctxt->vstateNr >= 1)
326
522k
  ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
327
13.9k
    else
328
13.9k
  ctxt->vstate = NULL;
329
535k
    return(ctxt->vstateNr);
330
535k
}
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
6.60k
{
434
6.60k
    if (ctxt->nodeMax <= 0) {
435
6.44k
        ctxt->nodeMax = 4;
436
6.44k
        ctxt->nodeTab =
437
6.44k
            (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
438
6.44k
                                     sizeof(ctxt->nodeTab[0]));
439
6.44k
        if (ctxt->nodeTab == NULL) {
440
0
      xmlVErrMemory(ctxt, "malloc failed");
441
0
            ctxt->nodeMax = 0;
442
0
            return (0);
443
0
        }
444
6.44k
    }
445
6.60k
    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
6.60k
    ctxt->nodeTab[ctxt->nodeNr] = value;
457
6.60k
    ctxt->node = value;
458
6.60k
    return (ctxt->nodeNr++);
459
6.60k
}
460
static xmlNodePtr
461
nodeVPop(xmlValidCtxtPtr ctxt)
462
326k
{
463
326k
    xmlNodePtr ret;
464
465
326k
    if (ctxt->nodeNr <= 0)
466
320k
        return (NULL);
467
6.30k
    ctxt->nodeNr--;
468
6.30k
    if (ctxt->nodeNr > 0)
469
81
        ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
470
6.22k
    else
471
6.22k
        ctxt->node = NULL;
472
6.30k
    ret = ctxt->nodeTab[ctxt->nodeNr];
473
6.30k
    ctxt->nodeTab[ctxt->nodeNr] = NULL;
474
6.30k
    return (ret);
475
326k
}
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.10M
   if (doc == NULL) return(0);         \
627
7.10M
   else if ((doc->intSubset == NULL) &&       \
628
7.10M
      (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
506k
               const xmlChar *name) {
652
506k
    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
506k
    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
439k
  case XML_ELEMENT_CONTENT_ELEMENT: {
666
439k
      xmlAutomataStatePtr oldstate = ctxt->state;
667
439k
      xmlChar fn[50];
668
439k
      xmlChar *fullname;
669
670
439k
      fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
671
439k
      if (fullname == NULL) {
672
0
          xmlVErrMemory(ctxt, "Building content model");
673
0
    return(0);
674
0
      }
675
676
439k
      switch (content->ocur) {
677
353k
    case XML_ELEMENT_CONTENT_ONCE:
678
353k
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
679
353k
          ctxt->state, NULL, fullname, NULL);
680
353k
        break;
681
29.1k
    case XML_ELEMENT_CONTENT_OPT:
682
29.1k
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
683
29.1k
          ctxt->state, NULL, fullname, NULL);
684
29.1k
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
685
29.1k
        break;
686
21.7k
    case XML_ELEMENT_CONTENT_PLUS:
687
21.7k
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
688
21.7k
          ctxt->state, NULL, fullname, NULL);
689
21.7k
        xmlAutomataNewTransition(ctxt->am, ctxt->state,
690
21.7k
                           ctxt->state, fullname, NULL);
691
21.7k
        break;
692
35.7k
    case XML_ELEMENT_CONTENT_MULT:
693
35.7k
        ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
694
35.7k
              ctxt->state, NULL);
695
35.7k
        xmlAutomataNewTransition(ctxt->am,
696
35.7k
          ctxt->state, ctxt->state, fullname, NULL);
697
35.7k
        break;
698
439k
      }
699
439k
      if ((fullname != fn) && (fullname != content->name))
700
167
    xmlFree(fullname);
701
439k
      break;
702
439k
  }
703
31.3k
  case XML_ELEMENT_CONTENT_SEQ: {
704
31.3k
      xmlAutomataStatePtr oldstate, oldend;
705
31.3k
      xmlElementContentOccur ocur;
706
707
      /*
708
       * Simply iterate over the content
709
       */
710
31.3k
      oldstate = ctxt->state;
711
31.3k
      ocur = content->ocur;
712
31.3k
      if (ocur != XML_ELEMENT_CONTENT_ONCE) {
713
1.78k
    ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
714
1.78k
    oldstate = ctxt->state;
715
1.78k
      }
716
87.9k
      do {
717
87.9k
    xmlValidBuildAContentModel(content->c1, ctxt, name);
718
87.9k
    content = content->c2;
719
87.9k
      } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
720
87.9k
         (content->ocur == XML_ELEMENT_CONTENT_ONCE));
721
31.3k
      xmlValidBuildAContentModel(content, ctxt, name);
722
31.3k
      oldend = ctxt->state;
723
31.3k
      ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
724
31.3k
      switch (ocur) {
725
29.5k
    case XML_ELEMENT_CONTENT_ONCE:
726
29.5k
        break;
727
426
    case XML_ELEMENT_CONTENT_OPT:
728
426
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
729
426
        break;
730
192
    case XML_ELEMENT_CONTENT_MULT:
731
192
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
732
192
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
733
192
        break;
734
1.16k
    case XML_ELEMENT_CONTENT_PLUS:
735
1.16k
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
736
1.16k
        break;
737
31.3k
      }
738
31.3k
      break;
739
31.3k
  }
740
34.8k
  case XML_ELEMENT_CONTENT_OR: {
741
34.8k
      xmlAutomataStatePtr oldstate, oldend;
742
34.8k
      xmlElementContentOccur ocur;
743
744
34.8k
      ocur = content->ocur;
745
34.8k
      if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
746
34.8k
    (ocur == XML_ELEMENT_CONTENT_MULT)) {
747
31.0k
    ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
748
31.0k
      ctxt->state, NULL);
749
31.0k
      }
750
34.8k
      oldstate = ctxt->state;
751
34.8k
      oldend = xmlAutomataNewState(ctxt->am);
752
753
      /*
754
       * iterate over the subtypes and remerge the end with an
755
       * epsilon transition
756
       */
757
260k
      do {
758
260k
    ctxt->state = oldstate;
759
260k
    xmlValidBuildAContentModel(content->c1, ctxt, name);
760
260k
    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
761
260k
    content = content->c2;
762
260k
      } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
763
260k
         (content->ocur == XML_ELEMENT_CONTENT_ONCE));
764
34.8k
      ctxt->state = oldstate;
765
34.8k
      xmlValidBuildAContentModel(content, ctxt, name);
766
34.8k
      xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
767
34.8k
      ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
768
34.8k
      switch (ocur) {
769
2.19k
    case XML_ELEMENT_CONTENT_ONCE:
770
2.19k
        break;
771
1.66k
    case XML_ELEMENT_CONTENT_OPT:
772
1.66k
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
773
1.66k
        break;
774
18.5k
    case XML_ELEMENT_CONTENT_MULT:
775
18.5k
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
776
18.5k
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
777
18.5k
        break;
778
12.4k
    case XML_ELEMENT_CONTENT_PLUS:
779
12.4k
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
780
12.4k
        break;
781
34.8k
      }
782
34.8k
      break;
783
34.8k
  }
784
34.8k
  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
506k
    }
790
506k
    return(1);
791
506k
}
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
91.7k
xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
804
805
91.7k
    if ((ctxt == NULL) || (elem == NULL))
806
0
  return(0);
807
91.7k
    if (elem->type != XML_ELEMENT_DECL)
808
0
  return(0);
809
91.7k
    if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
810
0
  return(1);
811
    /* TODO: should we rebuild in this case ? */
812
91.7k
    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
91.7k
    ctxt->am = xmlNewAutomata();
821
91.7k
    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
91.7k
    ctxt->state = xmlAutomataGetInitState(ctxt->am);
829
91.7k
    xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
830
91.7k
    xmlAutomataSetFinalState(ctxt->am, ctxt->state);
831
91.7k
    elem->contModel = xmlAutomataCompile(ctxt->am);
832
91.7k
    if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
833
1.03k
  char expr[5000];
834
1.03k
  expr[0] = 0;
835
1.03k
  xmlSnprintfElementContent(expr, 5000, elem->content, 1);
836
1.03k
  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
837
1.03k
                  XML_DTD_CONTENT_NOT_DETERMINIST,
838
1.03k
         "Content model of %s is not deterministic: %s\n",
839
1.03k
         elem->name, BAD_CAST expr, NULL);
840
#ifdef DEBUG_REGEXP_ALGO
841
        xmlRegexpPrint(stderr, elem->contModel);
842
#endif
843
1.03k
        ctxt->valid = 0;
844
1.03k
  ctxt->state = NULL;
845
1.03k
  xmlFreeAutomata(ctxt->am);
846
1.03k
  ctxt->am = NULL;
847
1.03k
  return(0);
848
1.03k
    }
849
90.6k
    ctxt->state = NULL;
850
90.6k
    xmlFreeAutomata(ctxt->am);
851
90.6k
    ctxt->am = NULL;
852
90.6k
    return(1);
853
91.7k
}
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
14.2M
                        xmlElementContentType type) {
913
14.2M
    xmlElementContentPtr ret;
914
14.2M
    xmlDictPtr dict = NULL;
915
916
14.2M
    if (doc != NULL)
917
14.2M
        dict = doc->dict;
918
919
14.2M
    switch(type) {
920
7.23M
  case XML_ELEMENT_CONTENT_ELEMENT:
921
7.23M
      if (name == NULL) {
922
0
          xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
923
0
      "xmlNewElementContent : name == NULL !\n",
924
0
      NULL);
925
0
      }
926
7.23M
      break;
927
677k
        case XML_ELEMENT_CONTENT_PCDATA:
928
1.73M
  case XML_ELEMENT_CONTENT_SEQ:
929
7.02M
  case XML_ELEMENT_CONTENT_OR:
930
7.02M
      if (name != NULL) {
931
0
          xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
932
0
      "xmlNewElementContent : name != NULL !\n",
933
0
      NULL);
934
0
      }
935
7.02M
      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
14.2M
    }
942
14.2M
    ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
943
14.2M
    if (ret == NULL) {
944
0
  xmlVErrMemory(NULL, "malloc failed");
945
0
  return(NULL);
946
0
    }
947
14.2M
    memset(ret, 0, sizeof(xmlElementContent));
948
14.2M
    ret->type = type;
949
14.2M
    ret->ocur = XML_ELEMENT_CONTENT_ONCE;
950
14.2M
    if (name != NULL) {
951
7.23M
        int l;
952
7.23M
  const xmlChar *tmp;
953
954
7.23M
  tmp = xmlSplitQName3(name, &l);
955
7.23M
  if (tmp == NULL) {
956
6.86M
      if (dict == NULL)
957
2.47M
    ret->name = xmlStrdup(name);
958
4.38M
      else
959
4.38M
          ret->name = xmlDictLookup(dict, name, -1);
960
6.86M
  } else {
961
372k
      if (dict == NULL) {
962
103k
    ret->prefix = xmlStrndup(name, l);
963
103k
    ret->name = xmlStrdup(tmp);
964
269k
      } else {
965
269k
          ret->prefix = xmlDictLookup(dict, name, l);
966
269k
    ret->name = xmlDictLookup(dict, tmp, -1);
967
269k
      }
968
372k
  }
969
7.23M
    }
970
14.2M
    return(ret);
971
14.2M
}
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.96M
xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1093
1.96M
    xmlDictPtr dict = NULL;
1094
1.96M
    size_t depth = 0;
1095
1096
1.96M
    if (cur == NULL)
1097
380k
        return;
1098
1.58M
    if (doc != NULL)
1099
1.57M
        dict = doc->dict;
1100
1101
14.2M
    while (1) {
1102
14.2M
        xmlElementContentPtr parent;
1103
1104
20.6M
        while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
1105
6.34M
            cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
1106
6.34M
            depth += 1;
1107
6.34M
        }
1108
1109
14.2M
  switch (cur->type) {
1110
677k
      case XML_ELEMENT_CONTENT_PCDATA:
1111
7.91M
      case XML_ELEMENT_CONTENT_ELEMENT:
1112
8.97M
      case XML_ELEMENT_CONTENT_SEQ:
1113
14.2M
      case XML_ELEMENT_CONTENT_OR:
1114
14.2M
    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
14.2M
  }
1121
14.2M
  if (dict) {
1122
9.17M
      if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1123
0
          xmlFree((xmlChar *) cur->name);
1124
9.17M
      if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1125
0
          xmlFree((xmlChar *) cur->prefix);
1126
9.17M
  } else {
1127
5.08M
      if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1128
5.08M
      if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1129
5.08M
  }
1130
14.2M
        parent = cur->parent;
1131
14.2M
        if ((depth == 0) || (parent == NULL)) {
1132
1.58M
            xmlFree(cur);
1133
1.58M
            break;
1134
1.58M
        }
1135
12.6M
        if (cur == parent->c1)
1136
6.34M
            parent->c1 = NULL;
1137
6.33M
        else
1138
6.33M
            parent->c2 = NULL;
1139
12.6M
  xmlFree(cur);
1140
1141
12.6M
        if (parent->c2 != NULL) {
1142
6.33M
      cur = parent->c2;
1143
6.34M
        } else {
1144
6.34M
            depth -= 1;
1145
6.34M
            cur = parent;
1146
6.34M
        }
1147
12.6M
    }
1148
1.58M
}
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
658k
xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
1172
658k
    switch (cur->ocur) {
1173
559k
        case XML_ELEMENT_CONTENT_ONCE:
1174
559k
            break;
1175
20.6k
        case XML_ELEMENT_CONTENT_OPT:
1176
20.6k
            xmlBufferWriteChar(buf, "?");
1177
20.6k
            break;
1178
68.4k
        case XML_ELEMENT_CONTENT_MULT:
1179
68.4k
            xmlBufferWriteChar(buf, "*");
1180
68.4k
            break;
1181
9.36k
        case XML_ELEMENT_CONTENT_PLUS:
1182
9.36k
            xmlBufferWriteChar(buf, "+");
1183
9.36k
            break;
1184
658k
    }
1185
658k
}
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
106k
xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
1196
106k
    xmlElementContentPtr cur;
1197
1198
106k
    if (content == NULL) return;
1199
1200
106k
    xmlBufferWriteChar(buf, "(");
1201
106k
    cur = content;
1202
1203
658k
    do {
1204
658k
        if (cur == NULL) return;
1205
1206
658k
        switch (cur->type) {
1207
47.0k
            case XML_ELEMENT_CONTENT_PCDATA:
1208
47.0k
                xmlBufferWriteChar(buf, "#PCDATA");
1209
47.0k
                break;
1210
335k
            case XML_ELEMENT_CONTENT_ELEMENT:
1211
335k
                if (cur->prefix != NULL) {
1212
71.1k
                    xmlBufferWriteCHAR(buf, cur->prefix);
1213
71.1k
                    xmlBufferWriteChar(buf, ":");
1214
71.1k
                }
1215
335k
                xmlBufferWriteCHAR(buf, cur->name);
1216
335k
                break;
1217
35.4k
            case XML_ELEMENT_CONTENT_SEQ:
1218
275k
            case XML_ELEMENT_CONTENT_OR:
1219
275k
                if ((cur != content) &&
1220
275k
                    (cur->parent != NULL) &&
1221
275k
                    ((cur->type != cur->parent->type) ||
1222
226k
                     (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1223
3.15k
                    xmlBufferWriteChar(buf, "(");
1224
275k
                cur = cur->c1;
1225
275k
                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
658k
        }
1231
1232
658k
        while (cur != content) {
1233
551k
            xmlElementContentPtr parent = cur->parent;
1234
1235
551k
            if (parent == NULL) return;
1236
1237
551k
            if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
1238
551k
                 (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
1239
551k
                ((cur->type != parent->type) ||
1240
226k
                 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1241
3.15k
                xmlBufferWriteChar(buf, ")");
1242
551k
            xmlDumpElementOccur(buf, cur);
1243
1244
551k
            if (cur == parent->c1) {
1245
275k
                if (parent->type == XML_ELEMENT_CONTENT_SEQ)
1246
35.4k
                    xmlBufferWriteChar(buf, " , ");
1247
240k
                else if (parent->type == XML_ELEMENT_CONTENT_OR)
1248
240k
                    xmlBufferWriteChar(buf, " | ");
1249
1250
275k
                cur = parent->c2;
1251
275k
                break;
1252
275k
            }
1253
1254
275k
            cur = parent;
1255
275k
        }
1256
658k
    } while (cur != content);
1257
1258
106k
    xmlBufferWriteChar(buf, ")");
1259
106k
    xmlDumpElementOccur(buf, content);
1260
106k
}
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
129k
xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1289
129k
    int len;
1290
1291
129k
    if (content == NULL) return;
1292
129k
    len = strlen(buf);
1293
129k
    if (size - len < 50) {
1294
6
  if ((size - len > 4) && (buf[len - 1] != '.'))
1295
6
      strcat(buf, " ...");
1296
6
  return;
1297
6
    }
1298
129k
    if (englob) strcat(buf, "(");
1299
129k
    switch (content->type) {
1300
0
        case XML_ELEMENT_CONTENT_PCDATA:
1301
0
            strcat(buf, "#PCDATA");
1302
0
      break;
1303
71.8k
  case XML_ELEMENT_CONTENT_ELEMENT: {
1304
71.8k
            int qnameLen = xmlStrlen(content->name);
1305
1306
71.8k
      if (content->prefix != NULL)
1307
45.3k
                qnameLen += xmlStrlen(content->prefix) + 1;
1308
71.8k
      if (size - len < qnameLen + 10) {
1309
114
    strcat(buf, " ...");
1310
114
    return;
1311
114
      }
1312
71.7k
      if (content->prefix != NULL) {
1313
45.2k
    strcat(buf, (char *) content->prefix);
1314
45.2k
    strcat(buf, ":");
1315
45.2k
      }
1316
71.7k
      if (content->name != NULL)
1317
71.7k
    strcat(buf, (char *) content->name);
1318
71.7k
      break;
1319
71.8k
        }
1320
7.26k
  case XML_ELEMENT_CONTENT_SEQ:
1321
7.26k
      if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1322
7.26k
          (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1323
962
    xmlSnprintfElementContent(buf, size, content->c1, 1);
1324
6.30k
      else
1325
6.30k
    xmlSnprintfElementContent(buf, size, content->c1, 0);
1326
7.26k
      len = strlen(buf);
1327
7.26k
      if (size - len < 50) {
1328
9
    if ((size - len > 4) && (buf[len - 1] != '.'))
1329
9
        strcat(buf, " ...");
1330
9
    return;
1331
9
      }
1332
7.25k
            strcat(buf, " , ");
1333
7.25k
      if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1334
7.25k
     (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1335
7.25k
    (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1336
644
    xmlSnprintfElementContent(buf, size, content->c2, 1);
1337
6.61k
      else
1338
6.61k
    xmlSnprintfElementContent(buf, size, content->c2, 0);
1339
7.25k
      break;
1340
50.1k
  case XML_ELEMENT_CONTENT_OR:
1341
50.1k
      if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1342
50.1k
          (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1343
272
    xmlSnprintfElementContent(buf, size, content->c1, 1);
1344
49.8k
      else
1345
49.8k
    xmlSnprintfElementContent(buf, size, content->c1, 0);
1346
50.1k
      len = strlen(buf);
1347
50.1k
      if (size - len < 50) {
1348
21
    if ((size - len > 4) && (buf[len - 1] != '.'))
1349
21
        strcat(buf, " ...");
1350
21
    return;
1351
21
      }
1352
50.1k
            strcat(buf, " | ");
1353
50.1k
      if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1354
50.1k
     (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1355
50.1k
    (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1356
221
    xmlSnprintfElementContent(buf, size, content->c2, 1);
1357
49.8k
      else
1358
49.8k
    xmlSnprintfElementContent(buf, size, content->c2, 0);
1359
50.1k
      break;
1360
129k
    }
1361
129k
    if (size - strlen(buf) <= 2) return;
1362
129k
    if (englob)
1363
16.5k
        strcat(buf, ")");
1364
129k
    switch (content->ocur) {
1365
114k
        case XML_ELEMENT_CONTENT_ONCE:
1366
114k
      break;
1367
2.59k
        case XML_ELEMENT_CONTENT_OPT:
1368
2.59k
      strcat(buf, "?");
1369
2.59k
      break;
1370
10.4k
        case XML_ELEMENT_CONTENT_MULT:
1371
10.4k
      strcat(buf, "*");
1372
10.4k
      break;
1373
1.79k
        case XML_ELEMENT_CONTENT_PLUS:
1374
1.79k
      strcat(buf, "+");
1375
1.79k
      break;
1376
129k
    }
1377
129k
}
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
1.78M
xmlFreeElement(xmlElementPtr elem) {
1393
1.78M
    if (elem == NULL) return;
1394
1.78M
    xmlUnlinkNode((xmlNodePtr) elem);
1395
1.78M
    xmlFreeDocElementContent(elem->doc, elem->content);
1396
1.78M
    if (elem->name != NULL)
1397
1.78M
  xmlFree((xmlChar *) elem->name);
1398
1.78M
    if (elem->prefix != NULL)
1399
304k
  xmlFree((xmlChar *) elem->prefix);
1400
1.78M
#ifdef LIBXML_REGEXP_ENABLED
1401
1.78M
    if (elem->contModel != NULL)
1402
91.7k
  xmlRegFreeRegexp(elem->contModel);
1403
1.78M
#endif
1404
1.78M
    xmlFree(elem);
1405
1.78M
}
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.78M
      xmlElementContentPtr content) {
1425
1.78M
    xmlElementPtr ret;
1426
1.78M
    xmlElementTablePtr table;
1427
1.78M
    xmlAttributePtr oldAttributes = NULL;
1428
1.78M
    xmlChar *ns, *uqname;
1429
1430
1.78M
    if (dtd == NULL) {
1431
0
  return(NULL);
1432
0
    }
1433
1.78M
    if (name == NULL) {
1434
0
  return(NULL);
1435
0
    }
1436
1437
1.78M
    switch (type) {
1438
338k
        case XML_ELEMENT_TYPE_EMPTY:
1439
338k
      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
338k
      break;
1446
338k
  case XML_ELEMENT_TYPE_ANY:
1447
4.26k
      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
4.26k
      break;
1454
631k
  case XML_ELEMENT_TYPE_MIXED:
1455
631k
      if (content == NULL) {
1456
225
    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1457
225
            "xmlAddElementDecl: content == NULL for MIXED\n",
1458
225
      NULL);
1459
225
    return(NULL);
1460
225
      }
1461
631k
      break;
1462
813k
  case XML_ELEMENT_TYPE_ELEMENT:
1463
813k
      if (content == NULL) {
1464
1.53k
    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1465
1.53k
            "xmlAddElementDecl: content == NULL for ELEMENT\n",
1466
1.53k
      NULL);
1467
1.53k
    return(NULL);
1468
1.53k
      }
1469
811k
      break;
1470
811k
  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.78M
    }
1476
1477
    /*
1478
     * check if name is a QName
1479
     */
1480
1.78M
    uqname = xmlSplitQName2(name, &ns);
1481
1.78M
    if (uqname != NULL)
1482
295k
  name = uqname;
1483
1484
    /*
1485
     * Create the Element table if needed.
1486
     */
1487
1.78M
    table = (xmlElementTablePtr) dtd->elements;
1488
1.78M
    if (table == NULL) {
1489
152k
  xmlDictPtr dict = NULL;
1490
1491
152k
  if (dtd->doc != NULL)
1492
152k
      dict = dtd->doc->dict;
1493
152k
        table = xmlHashCreateDict(0, dict);
1494
152k
  dtd->elements = (void *) table;
1495
152k
    }
1496
1.78M
    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.78M
    if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1511
1.78M
  ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1512
1.78M
  if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1513
2.74k
      oldAttributes = ret->attributes;
1514
2.74k
      ret->attributes = NULL;
1515
2.74k
      xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1516
2.74k
      xmlFreeElement(ret);
1517
2.74k
  }
1518
1.78M
    }
1519
1520
    /*
1521
     * The element may already be present if one of its attribute
1522
     * was registered first
1523
     */
1524
1.78M
    ret = xmlHashLookup2(table, name, ns);
1525
1.78M
    if (ret != NULL) {
1526
42.9k
  if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1527
42.8k
#ifdef LIBXML_VALID_ENABLED
1528
      /*
1529
       * The element is already defined in this DTD.
1530
       */
1531
42.8k
      xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1532
42.8k
                      "Redefinition of element %s\n",
1533
42.8k
          name, NULL, NULL);
1534
42.8k
#endif /* LIBXML_VALID_ENABLED */
1535
42.8k
      if (uqname != NULL)
1536
157
    xmlFree(uqname);
1537
42.8k
            if (ns != NULL)
1538
157
          xmlFree(ns);
1539
42.8k
      return(NULL);
1540
42.8k
  }
1541
60
  if (ns != NULL) {
1542
0
      xmlFree(ns);
1543
0
      ns = NULL;
1544
0
  }
1545
1.74M
    } else {
1546
1.74M
  ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1547
1.74M
  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
1.74M
  memset(ret, 0, sizeof(xmlElement));
1556
1.74M
  ret->type = XML_ELEMENT_DECL;
1557
1558
  /*
1559
   * fill the structure.
1560
   */
1561
1.74M
  ret->name = xmlStrdup(name);
1562
1.74M
  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
1.74M
  ret->prefix = ns;
1572
1573
  /*
1574
   * Validity Check:
1575
   * Insertion must not fail
1576
   */
1577
1.74M
  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
1.74M
  ret->attributes = oldAttributes;
1596
1.74M
    }
1597
1598
    /*
1599
     * Finish to fill the structure.
1600
     */
1601
1.74M
    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
1.74M
    if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) {
1608
1.74M
  ret->content = content;
1609
1.74M
  if (content != NULL)
1610
1.40M
      content->parent = (xmlElementContentPtr) 1;
1611
1.74M
    } else {
1612
0
  ret->content = xmlCopyDocElementContent(dtd->doc, content);
1613
0
    }
1614
1615
    /*
1616
     * Link it to the DTD
1617
     */
1618
1.74M
    ret->parent = dtd;
1619
1.74M
    ret->doc = dtd->doc;
1620
1.74M
    if (dtd->last == NULL) {
1621
127k
  dtd->children = dtd->last = (xmlNodePtr) ret;
1622
1.61M
    } else {
1623
1.61M
        dtd->last->next = (xmlNodePtr) ret;
1624
1.61M
  ret->prev = dtd->last;
1625
1.61M
  dtd->last = (xmlNodePtr) ret;
1626
1.61M
    }
1627
1.74M
    if (uqname != NULL)
1628
295k
  xmlFree(uqname);
1629
1.74M
    return(ret);
1630
1.78M
}
1631
1632
static void
1633
1.77M
xmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) {
1634
1.77M
    xmlFreeElement((xmlElementPtr) elem);
1635
1.77M
}
1636
1637
/**
1638
 * xmlFreeElementTable:
1639
 * @table:  An element table
1640
 *
1641
 * Deallocate the memory used by an element hash table.
1642
 */
1643
void
1644
171k
xmlFreeElementTable(xmlElementTablePtr table) {
1645
171k
    xmlHashFree(table, xmlFreeElementTableEntry);
1646
171k
}
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
166k
xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1709
166k
    if ((buf == NULL) || (elem == NULL))
1710
0
        return;
1711
166k
    switch (elem->etype) {
1712
59.2k
  case XML_ELEMENT_TYPE_EMPTY:
1713
59.2k
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1714
59.2k
      if (elem->prefix != NULL) {
1715
29.5k
    xmlBufferWriteCHAR(buf, elem->prefix);
1716
29.5k
    xmlBufferWriteChar(buf, ":");
1717
29.5k
      }
1718
59.2k
      xmlBufferWriteCHAR(buf, elem->name);
1719
59.2k
      xmlBufferWriteChar(buf, " EMPTY>\n");
1720
59.2k
      break;
1721
294
  case XML_ELEMENT_TYPE_ANY:
1722
294
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1723
294
      if (elem->prefix != NULL) {
1724
12
    xmlBufferWriteCHAR(buf, elem->prefix);
1725
12
    xmlBufferWriteChar(buf, ":");
1726
12
      }
1727
294
      xmlBufferWriteCHAR(buf, elem->name);
1728
294
      xmlBufferWriteChar(buf, " ANY>\n");
1729
294
      break;
1730
47.0k
  case XML_ELEMENT_TYPE_MIXED:
1731
47.0k
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1732
47.0k
      if (elem->prefix != NULL) {
1733
1.10k
    xmlBufferWriteCHAR(buf, elem->prefix);
1734
1.10k
    xmlBufferWriteChar(buf, ":");
1735
1.10k
      }
1736
47.0k
      xmlBufferWriteCHAR(buf, elem->name);
1737
47.0k
      xmlBufferWriteChar(buf, " ");
1738
47.0k
      xmlDumpElementContent(buf, elem->content);
1739
47.0k
      xmlBufferWriteChar(buf, ">\n");
1740
47.0k
      break;
1741
59.9k
  case XML_ELEMENT_TYPE_ELEMENT:
1742
59.9k
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1743
59.9k
      if (elem->prefix != NULL) {
1744
28.0k
    xmlBufferWriteCHAR(buf, elem->prefix);
1745
28.0k
    xmlBufferWriteChar(buf, ":");
1746
28.0k
      }
1747
59.9k
      xmlBufferWriteCHAR(buf, elem->name);
1748
59.9k
      xmlBufferWriteChar(buf, " ");
1749
59.9k
      xmlDumpElementContent(buf, elem->content);
1750
59.9k
      xmlBufferWriteChar(buf, ">\n");
1751
59.9k
      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
166k
    }
1757
166k
}
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
950k
xmlCreateEnumeration(const xmlChar *name) {
1799
950k
    xmlEnumerationPtr ret;
1800
1801
950k
    ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1802
950k
    if (ret == NULL) {
1803
0
  xmlVErrMemory(NULL, "malloc failed");
1804
0
        return(NULL);
1805
0
    }
1806
950k
    memset(ret, 0, sizeof(xmlEnumeration));
1807
1808
950k
    if (name != NULL)
1809
950k
        ret->name = xmlStrdup(name);
1810
950k
    return(ret);
1811
950k
}
1812
1813
/**
1814
 * xmlFreeEnumeration:
1815
 * @cur:  the tree to free.
1816
 *
1817
 * free an enumeration attribute node (recursive).
1818
 */
1819
void
1820
951k
xmlFreeEnumeration(xmlEnumerationPtr cur) {
1821
951k
    if (cur == NULL) return;
1822
1823
950k
    if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1824
1825
950k
    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1826
950k
    xmlFree(cur);
1827
950k
}
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
119k
xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1864
119k
    if ((buf == NULL) || (cur == NULL))
1865
0
        return;
1866
1867
119k
    xmlBufferWriteCHAR(buf, cur->name);
1868
119k
    if (cur->next == NULL)
1869
41.5k
  xmlBufferWriteChar(buf, ")");
1870
77.5k
    else {
1871
77.5k
  xmlBufferWriteChar(buf, " | ");
1872
77.5k
  xmlDumpEnumeration(buf, cur->next);
1873
77.5k
    }
1874
119k
}
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
1.81M
xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1891
1.81M
    xmlAttributePtr cur;
1892
1.81M
    int ret = 0;
1893
1894
1.81M
    if (elem == NULL) return(0);
1895
1.81M
    cur = elem->attributes;
1896
2.62M
    while (cur != NULL) {
1897
802k
        if (cur->atype == XML_ATTRIBUTE_ID) {
1898
721k
      ret ++;
1899
721k
      if ((ret > 1) && (err))
1900
8
    xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1901
8
         "Element %s has too many ID attributes defined : %s\n",
1902
8
           elem->name, cur->name, NULL);
1903
721k
  }
1904
802k
  cur = cur->nexth;
1905
802k
    }
1906
1.81M
    return(ret);
1907
1.81M
}
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.95M
xmlFreeAttribute(xmlAttributePtr attr) {
1918
3.95M
    xmlDictPtr dict;
1919
1920
3.95M
    if (attr == NULL) return;
1921
3.95M
    if (attr->doc != NULL)
1922
3.95M
  dict = attr->doc->dict;
1923
0
    else
1924
0
  dict = NULL;
1925
3.95M
    xmlUnlinkNode((xmlNodePtr) attr);
1926
3.95M
    if (attr->tree != NULL)
1927
294k
        xmlFreeEnumeration(attr->tree);
1928
3.95M
    if (dict) {
1929
2.40M
        if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1930
0
      xmlFree((xmlChar *) attr->elem);
1931
2.40M
        if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1932
0
      xmlFree((xmlChar *) attr->name);
1933
2.40M
        if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1934
0
      xmlFree((xmlChar *) attr->prefix);
1935
2.40M
        if ((attr->defaultValue != NULL) &&
1936
2.40M
      (!xmlDictOwns(dict, attr->defaultValue)))
1937
0
      xmlFree((xmlChar *) attr->defaultValue);
1938
2.40M
    } else {
1939
1.54M
  if (attr->elem != NULL)
1940
1.54M
      xmlFree((xmlChar *) attr->elem);
1941
1.54M
  if (attr->name != NULL)
1942
1.54M
      xmlFree((xmlChar *) attr->name);
1943
1.54M
  if (attr->defaultValue != NULL)
1944
136k
      xmlFree((xmlChar *) attr->defaultValue);
1945
1.54M
  if (attr->prefix != NULL)
1946
117k
      xmlFree((xmlChar *) attr->prefix);
1947
1.54M
    }
1948
3.95M
    xmlFree(attr);
1949
3.95M
}
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.95M
        const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1975
3.95M
    xmlAttributePtr ret;
1976
3.95M
    xmlAttributeTablePtr table;
1977
3.95M
    xmlElementPtr elemDef;
1978
3.95M
    xmlDictPtr dict = NULL;
1979
1980
3.95M
    if (dtd == NULL) {
1981
0
  xmlFreeEnumeration(tree);
1982
0
  return(NULL);
1983
0
    }
1984
3.95M
    if (name == NULL) {
1985
0
  xmlFreeEnumeration(tree);
1986
0
  return(NULL);
1987
0
    }
1988
3.95M
    if (elem == NULL) {
1989
0
  xmlFreeEnumeration(tree);
1990
0
  return(NULL);
1991
0
    }
1992
3.95M
    if (dtd->doc != NULL)
1993
3.95M
  dict = dtd->doc->dict;
1994
1995
3.95M
#ifdef LIBXML_VALID_ENABLED
1996
    /*
1997
     * Check the type and possibly the default value.
1998
     */
1999
3.95M
    switch (type) {
2000
1.31M
        case XML_ATTRIBUTE_CDATA:
2001
1.31M
      break;
2002
1.11M
        case XML_ATTRIBUTE_ID:
2003
1.11M
      break;
2004
79.0k
        case XML_ATTRIBUTE_IDREF:
2005
79.0k
      break;
2006
13.5k
        case XML_ATTRIBUTE_IDREFS:
2007
13.5k
      break;
2008
6.33k
        case XML_ATTRIBUTE_ENTITY:
2009
6.33k
      break;
2010
781
        case XML_ATTRIBUTE_ENTITIES:
2011
781
      break;
2012
981k
        case XML_ATTRIBUTE_NMTOKEN:
2013
981k
      break;
2014
146k
        case XML_ATTRIBUTE_NMTOKENS:
2015
146k
      break;
2016
293k
        case XML_ATTRIBUTE_ENUMERATION:
2017
293k
      break;
2018
536
        case XML_ATTRIBUTE_NOTATION:
2019
536
      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.95M
    }
2027
3.95M
    if ((defaultValue != NULL) &&
2028
3.95M
        (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
2029
22.5k
  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2030
22.5k
                  "Attribute %s of %s: invalid default value\n",
2031
22.5k
                  elem, name, defaultValue);
2032
22.5k
  defaultValue = NULL;
2033
22.5k
  if (ctxt != NULL)
2034
22.5k
      ctxt->valid = 0;
2035
22.5k
    }
2036
3.95M
#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.95M
    if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2043
3.95M
  (dtd->doc->intSubset != NULL) &&
2044
3.95M
  (dtd->doc->intSubset->attributes != NULL)) {
2045
274k
        ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2046
274k
  if (ret != NULL) {
2047
27
      xmlFreeEnumeration(tree);
2048
27
      return(NULL);
2049
27
  }
2050
274k
    }
2051
2052
    /*
2053
     * Create the Attribute table if needed.
2054
     */
2055
3.95M
    table = (xmlAttributeTablePtr) dtd->attributes;
2056
3.95M
    if (table == NULL) {
2057
119k
        table = xmlHashCreateDict(0, dict);
2058
119k
  dtd->attributes = (void *) table;
2059
119k
    }
2060
3.95M
    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.95M
    ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2069
3.95M
    if (ret == NULL) {
2070
0
  xmlVErrMemory(ctxt, "malloc failed");
2071
0
  xmlFreeEnumeration(tree);
2072
0
  return(NULL);
2073
0
    }
2074
3.95M
    memset(ret, 0, sizeof(xmlAttribute));
2075
3.95M
    ret->type = XML_ATTRIBUTE_DECL;
2076
2077
    /*
2078
     * fill the structure.
2079
     */
2080
3.95M
    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.95M
    ret->doc = dtd->doc;
2087
3.95M
    if (dict) {
2088
2.40M
  ret->name = xmlDictLookup(dict, name, -1);
2089
2.40M
  ret->prefix = xmlDictLookup(dict, ns, -1);
2090
2.40M
  ret->elem = xmlDictLookup(dict, elem, -1);
2091
2.40M
    } else {
2092
1.54M
  ret->name = xmlStrdup(name);
2093
1.54M
  ret->prefix = xmlStrdup(ns);
2094
1.54M
  ret->elem = xmlStrdup(elem);
2095
1.54M
    }
2096
3.95M
    ret->def = def;
2097
3.95M
    ret->tree = tree;
2098
3.95M
    if (defaultValue != NULL) {
2099
353k
        if (dict)
2100
217k
      ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2101
136k
  else
2102
136k
      ret->defaultValue = xmlStrdup(defaultValue);
2103
353k
    }
2104
2105
    /*
2106
     * Validity Check:
2107
     * Search the DTD for previous declarations of the ATTLIST
2108
     */
2109
3.95M
    if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2110
134k
#ifdef LIBXML_VALID_ENABLED
2111
  /*
2112
   * The attribute is already defined in this DTD.
2113
   */
2114
134k
  xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2115
134k
     "Attribute %s of element %s: already defined\n",
2116
134k
     name, elem, NULL);
2117
134k
#endif /* LIBXML_VALID_ENABLED */
2118
134k
  xmlFreeAttribute(ret);
2119
134k
  return(NULL);
2120
134k
    }
2121
2122
    /*
2123
     * Validity Check:
2124
     * Multiple ID per element
2125
     */
2126
3.81M
    elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2127
3.81M
    if (elemDef != NULL) {
2128
2129
3.81M
#ifdef LIBXML_VALID_ENABLED
2130
3.81M
        if ((type == XML_ATTRIBUTE_ID) &&
2131
3.81M
      (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2132
752
      xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2133
752
     "Element %s has too may ID attributes defined : %s\n",
2134
752
       elem, name, NULL);
2135
752
      if (ctxt != NULL)
2136
752
    ctxt->valid = 0;
2137
752
  }
2138
3.81M
#endif /* LIBXML_VALID_ENABLED */
2139
2140
  /*
2141
   * Insert namespace default def first they need to be
2142
   * processed first.
2143
   */
2144
3.81M
  if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2145
3.81M
      ((ret->prefix != NULL &&
2146
3.81M
       (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2147
38.1k
      ret->nexth = elemDef->attributes;
2148
38.1k
      elemDef->attributes = ret;
2149
3.77M
  } else {
2150
3.77M
      xmlAttributePtr tmp = elemDef->attributes;
2151
2152
3.77M
      while ((tmp != NULL) &&
2153
3.77M
       ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2154
2.40M
        ((ret->prefix != NULL &&
2155
2.40M
         (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2156
1.24k
    if (tmp->nexth == NULL)
2157
712
        break;
2158
528
    tmp = tmp->nexth;
2159
528
      }
2160
3.77M
      if (tmp != NULL) {
2161
2.40M
    ret->nexth = tmp->nexth;
2162
2.40M
          tmp->nexth = ret;
2163
2.40M
      } else {
2164
1.37M
    ret->nexth = elemDef->attributes;
2165
1.37M
    elemDef->attributes = ret;
2166
1.37M
      }
2167
3.77M
  }
2168
3.81M
    }
2169
2170
    /*
2171
     * Link it to the DTD
2172
     */
2173
3.81M
    ret->parent = dtd;
2174
3.81M
    if (dtd->last == NULL) {
2175
18.9k
  dtd->children = dtd->last = (xmlNodePtr) ret;
2176
3.79M
    } else {
2177
3.79M
        dtd->last->next = (xmlNodePtr) ret;
2178
3.79M
  ret->prev = dtd->last;
2179
3.79M
  dtd->last = (xmlNodePtr) ret;
2180
3.79M
    }
2181
3.81M
    return(ret);
2182
3.95M
}
2183
2184
static void
2185
3.81M
xmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) {
2186
3.81M
    xmlFreeAttribute((xmlAttributePtr) attr);
2187
3.81M
}
2188
2189
/**
2190
 * xmlFreeAttributeTable:
2191
 * @table:  An attribute table
2192
 *
2193
 * Deallocate the memory used by an entities hash table.
2194
 */
2195
void
2196
119k
xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2197
119k
    xmlHashFree(table, xmlFreeAttributeTableEntry);
2198
119k
}
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
325k
xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2260
325k
    if ((buf == NULL) || (attr == NULL))
2261
0
        return;
2262
325k
    xmlBufferWriteChar(buf, "<!ATTLIST ");
2263
325k
    xmlBufferWriteCHAR(buf, attr->elem);
2264
325k
    xmlBufferWriteChar(buf, " ");
2265
325k
    if (attr->prefix != NULL) {
2266
67.8k
  xmlBufferWriteCHAR(buf, attr->prefix);
2267
67.8k
  xmlBufferWriteChar(buf, ":");
2268
67.8k
    }
2269
325k
    xmlBufferWriteCHAR(buf, attr->name);
2270
325k
    switch (attr->atype) {
2271
138k
  case XML_ATTRIBUTE_CDATA:
2272
138k
      xmlBufferWriteChar(buf, " CDATA");
2273
138k
      break;
2274
62.0k
  case XML_ATTRIBUTE_ID:
2275
62.0k
      xmlBufferWriteChar(buf, " ID");
2276
62.0k
      break;
2277
7.16k
  case XML_ATTRIBUTE_IDREF:
2278
7.16k
      xmlBufferWriteChar(buf, " IDREF");
2279
7.16k
      break;
2280
2.40k
  case XML_ATTRIBUTE_IDREFS:
2281
2.40k
      xmlBufferWriteChar(buf, " IDREFS");
2282
2.40k
      break;
2283
1.37k
  case XML_ATTRIBUTE_ENTITY:
2284
1.37k
      xmlBufferWriteChar(buf, " ENTITY");
2285
1.37k
      break;
2286
300
  case XML_ATTRIBUTE_ENTITIES:
2287
300
      xmlBufferWriteChar(buf, " ENTITIES");
2288
300
      break;
2289
48.4k
  case XML_ATTRIBUTE_NMTOKEN:
2290
48.4k
      xmlBufferWriteChar(buf, " NMTOKEN");
2291
48.4k
      break;
2292
23.9k
  case XML_ATTRIBUTE_NMTOKENS:
2293
23.9k
      xmlBufferWriteChar(buf, " NMTOKENS");
2294
23.9k
      break;
2295
41.3k
  case XML_ATTRIBUTE_ENUMERATION:
2296
41.3k
      xmlBufferWriteChar(buf, " (");
2297
41.3k
      xmlDumpEnumeration(buf, attr->tree);
2298
41.3k
      break;
2299
136
  case XML_ATTRIBUTE_NOTATION:
2300
136
      xmlBufferWriteChar(buf, " NOTATION (");
2301
136
      xmlDumpEnumeration(buf, attr->tree);
2302
136
      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
325k
    }
2308
325k
    switch (attr->def) {
2309
20.7k
  case XML_ATTRIBUTE_NONE:
2310
20.7k
      break;
2311
64.5k
  case XML_ATTRIBUTE_REQUIRED:
2312
64.5k
      xmlBufferWriteChar(buf, " #REQUIRED");
2313
64.5k
      break;
2314
230k
  case XML_ATTRIBUTE_IMPLIED:
2315
230k
      xmlBufferWriteChar(buf, " #IMPLIED");
2316
230k
      break;
2317
10.4k
  case XML_ATTRIBUTE_FIXED:
2318
10.4k
      xmlBufferWriteChar(buf, " #FIXED");
2319
10.4k
      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
325k
    }
2325
325k
    if (attr->defaultValue != NULL) {
2326
25.6k
  xmlBufferWriteChar(buf, " ");
2327
25.6k
  xmlBufferWriteQuotedString(buf, attr->defaultValue);
2328
25.6k
    }
2329
325k
    xmlBufferWriteChar(buf, ">\n");
2330
325k
}
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
2.36k
xmlFreeNotation(xmlNotationPtr nota) {
2373
2.36k
    if (nota == NULL) return;
2374
2.36k
    if (nota->name != NULL)
2375
2.36k
  xmlFree((xmlChar *) nota->name);
2376
2.36k
    if (nota->PublicID != NULL)
2377
1.28k
  xmlFree((xmlChar *) nota->PublicID);
2378
2.36k
    if (nota->SystemID != NULL)
2379
1.15k
  xmlFree((xmlChar *) nota->SystemID);
2380
2.36k
    xmlFree(nota);
2381
2.36k
}
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
2.36k
                   const xmlChar *PublicID, const xmlChar *SystemID) {
2400
2.36k
    xmlNotationPtr ret;
2401
2.36k
    xmlNotationTablePtr table;
2402
2403
2.36k
    if (dtd == NULL) {
2404
0
  return(NULL);
2405
0
    }
2406
2.36k
    if (name == NULL) {
2407
0
  return(NULL);
2408
0
    }
2409
2.36k
    if ((PublicID == NULL) && (SystemID == NULL)) {
2410
0
  return(NULL);
2411
0
    }
2412
2413
    /*
2414
     * Create the Notation table if needed.
2415
     */
2416
2.36k
    table = (xmlNotationTablePtr) dtd->notations;
2417
2.36k
    if (table == NULL) {
2418
2.00k
  xmlDictPtr dict = NULL;
2419
2.00k
  if (dtd->doc != NULL)
2420
2.00k
      dict = dtd->doc->dict;
2421
2422
2.00k
        dtd->notations = table = xmlHashCreateDict(0, dict);
2423
2.00k
    }
2424
2.36k
    if (table == NULL) {
2425
0
  xmlVErrMemory(ctxt,
2426
0
    "xmlAddNotationDecl: Table creation failed!\n");
2427
0
        return(NULL);
2428
0
    }
2429
2430
2.36k
    ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2431
2.36k
    if (ret == NULL) {
2432
0
  xmlVErrMemory(ctxt, "malloc failed");
2433
0
  return(NULL);
2434
0
    }
2435
2.36k
    memset(ret, 0, sizeof(xmlNotation));
2436
2437
    /*
2438
     * fill the structure.
2439
     */
2440
2.36k
    ret->name = xmlStrdup(name);
2441
2.36k
    if (SystemID != NULL)
2442
1.15k
        ret->SystemID = xmlStrdup(SystemID);
2443
2.36k
    if (PublicID != NULL)
2444
1.28k
        ret->PublicID = xmlStrdup(PublicID);
2445
2446
    /*
2447
     * Validity Check:
2448
     * Check the DTD for previous declarations of the ATTLIST
2449
     */
2450
2.36k
    if (xmlHashAddEntry(table, name, ret)) {
2451
281
#ifdef LIBXML_VALID_ENABLED
2452
281
  xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2453
281
        "xmlAddNotationDecl: %s already defined\n",
2454
281
        (const char *) name);
2455
281
#endif /* LIBXML_VALID_ENABLED */
2456
281
  xmlFreeNotation(ret);
2457
281
  return(NULL);
2458
281
    }
2459
2.08k
    return(ret);
2460
2.36k
}
2461
2462
static void
2463
2.08k
xmlFreeNotationTableEntry(void *nota, const xmlChar *name ATTRIBUTE_UNUSED) {
2464
2.08k
    xmlFreeNotation((xmlNotationPtr) nota);
2465
2.08k
}
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.00k
xmlFreeNotationTable(xmlNotationTablePtr table) {
2475
2.00k
    xmlHashFree(table, xmlFreeNotationTableEntry);
2476
2.00k
}
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
677
xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2536
677
    if ((buf == NULL) || (nota == NULL))
2537
0
        return;
2538
677
    xmlBufferWriteChar(buf, "<!NOTATION ");
2539
677
    xmlBufferWriteCHAR(buf, nota->name);
2540
677
    if (nota->PublicID != NULL) {
2541
334
  xmlBufferWriteChar(buf, " PUBLIC ");
2542
334
  xmlBufferWriteQuotedString(buf, nota->PublicID);
2543
334
  if (nota->SystemID != NULL) {
2544
26
      xmlBufferWriteChar(buf, " ");
2545
26
      xmlBufferWriteQuotedString(buf, nota->SystemID);
2546
26
  }
2547
343
    } else {
2548
343
  xmlBufferWriteChar(buf, " SYSTEM ");
2549
343
  xmlBufferWriteQuotedString(buf, nota->SystemID);
2550
343
    }
2551
677
    xmlBufferWriteChar(buf, " >\n");
2552
677
}
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
677
                        const xmlChar *name ATTRIBUTE_UNUSED) {
2564
677
    xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2565
677
}
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
652
xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2576
652
    if ((buf == NULL) || (table == NULL))
2577
0
        return;
2578
652
    xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2579
652
}
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
515k
  if ((str) && ((!dict) ||       \
2596
515k
      (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))  \
2597
515k
      xmlFree((char *)(str));
2598
2599
/**
2600
 * xmlValidNormalizeString:
2601
 * @str: a string
2602
 *
2603
 * Normalize a string in-place.
2604
 */
2605
static void
2606
541k
xmlValidNormalizeString(xmlChar *str) {
2607
541k
    xmlChar *dst;
2608
541k
    const xmlChar *src;
2609
2610
541k
    if (str == NULL)
2611
0
        return;
2612
541k
    src = str;
2613
541k
    dst = str;
2614
2615
580k
    while (*src == 0x20) src++;
2616
5.27M
    while (*src != 0) {
2617
4.72M
  if (*src == 0x20) {
2618
112k
      while (*src == 0x20) src++;
2619
40.1k
      if (*src != 0)
2620
24.1k
    *dst++ = 0x20;
2621
4.68M
  } else {
2622
4.68M
      *dst++ = *src++;
2623
4.68M
  }
2624
4.72M
    }
2625
541k
    *dst = 0;
2626
541k
}
2627
2628
static int
2629
1.05M
xmlIsStreaming(xmlValidCtxtPtr ctxt) {
2630
1.05M
    xmlParserCtxtPtr pctxt;
2631
2632
1.05M
    if (ctxt == NULL)
2633
7.40k
        return(0);
2634
1.05M
    if ((ctxt->flags & XML_VCTXT_USE_PCTXT) == 0)
2635
0
        return(0);
2636
1.05M
    pctxt = ctxt->userData;
2637
1.05M
    return(pctxt->parseMode == XML_PARSE_READER);
2638
1.05M
}
2639
2640
/**
2641
 * xmlFreeID:
2642
 * @not:  A id
2643
 *
2644
 * Deallocate the memory used by an id definition
2645
 */
2646
static void
2647
473k
xmlFreeID(xmlIDPtr id) {
2648
473k
    xmlDictPtr dict = NULL;
2649
2650
473k
    if (id == NULL) return;
2651
2652
473k
    if (id->doc != NULL)
2653
473k
        dict = id->doc->dict;
2654
2655
473k
    if (id->value != NULL)
2656
473k
  DICT_FREE(id->value)
2657
473k
    if (id->name != NULL)
2658
41.8k
  DICT_FREE(id->name)
2659
473k
    xmlFree(id);
2660
473k
}
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
473k
         xmlAttrPtr attr) {
2677
473k
    xmlIDPtr ret;
2678
473k
    xmlIDTablePtr table;
2679
2680
473k
    if (doc == NULL) {
2681
0
  return(NULL);
2682
0
    }
2683
473k
    if ((value == NULL) || (value[0] == 0)) {
2684
412
  return(NULL);
2685
412
    }
2686
473k
    if (attr == NULL) {
2687
0
  return(NULL);
2688
0
    }
2689
2690
    /*
2691
     * Create the ID table if needed.
2692
     */
2693
473k
    table = (xmlIDTablePtr) doc->ids;
2694
473k
    if (table == NULL)  {
2695
40.7k
        doc->ids = table = xmlHashCreateDict(0, doc->dict);
2696
40.7k
    }
2697
473k
    if (table == NULL) {
2698
0
  xmlVErrMemory(ctxt,
2699
0
    "xmlAddID: Table creation failed!\n");
2700
0
        return(NULL);
2701
0
    }
2702
2703
473k
    ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2704
473k
    if (ret == NULL) {
2705
0
  xmlVErrMemory(ctxt, "malloc failed");
2706
0
  return(NULL);
2707
0
    }
2708
2709
    /*
2710
     * fill the structure.
2711
     */
2712
473k
    ret->value = xmlStrdup(value);
2713
473k
    ret->doc = doc;
2714
473k
    if (xmlIsStreaming(ctxt)) {
2715
  /*
2716
   * Operating in streaming mode, attr is gonna disappear
2717
   */
2718
41.8k
  if (doc->dict != NULL)
2719
15.9k
      ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2720
25.8k
  else
2721
25.8k
      ret->name = xmlStrdup(attr->name);
2722
41.8k
  ret->attr = NULL;
2723
431k
    } else {
2724
431k
  ret->attr = attr;
2725
431k
  ret->name = NULL;
2726
431k
    }
2727
473k
    ret->lineno = xmlGetLineNo(attr->parent);
2728
2729
473k
    if (xmlHashAddEntry(table, value, ret) < 0) {
2730
18.7k
#ifdef LIBXML_VALID_ENABLED
2731
  /*
2732
   * The id is already defined in this DTD.
2733
   */
2734
18.7k
  if (ctxt != NULL) {
2735
12.3k
      xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2736
12.3k
          "ID %s already defined\n", value, NULL, NULL);
2737
12.3k
  }
2738
18.7k
#endif /* LIBXML_VALID_ENABLED */
2739
18.7k
  xmlFreeID(ret);
2740
18.7k
  return(NULL);
2741
18.7k
    }
2742
454k
    if (attr != NULL)
2743
454k
  attr->atype = XML_ATTRIBUTE_ID;
2744
454k
    return(ret);
2745
473k
}
2746
2747
static void
2748
454k
xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) {
2749
454k
    xmlFreeID((xmlIDPtr) id);
2750
454k
}
2751
2752
/**
2753
 * xmlFreeIDTable:
2754
 * @table:  An id table
2755
 *
2756
 * Deallocate the memory used by an ID hash table.
2757
 */
2758
void
2759
40.7k
xmlFreeIDTable(xmlIDTablePtr table) {
2760
40.7k
    xmlHashFree(table, xmlFreeIDTableEntry);
2761
40.7k
}
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
24.2M
xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2778
24.2M
    if ((attr == NULL) || (attr->name == NULL)) return(0);
2779
24.2M
    if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2780
24.2M
        (!strcmp((char *) attr->name, "id")) &&
2781
24.2M
        (!strcmp((char *) attr->ns->prefix, "xml")))
2782
6.91k
  return(1);
2783
24.1M
    if (doc == NULL) return(0);
2784
24.1M
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2785
24.1M
        (doc->type != XML_HTML_DOCUMENT_NODE)) {
2786
19.5M
  return(0);
2787
19.5M
    } 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
4.61M
    } else if (elem == NULL) {
2794
0
  return(0);
2795
4.61M
    } else {
2796
4.61M
  xmlAttributePtr attrDecl = NULL;
2797
2798
4.61M
  xmlChar felem[50], fattr[50];
2799
4.61M
  xmlChar *fullelemname, *fullattrname;
2800
2801
4.61M
  fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2802
246k
      xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2803
4.61M
      (xmlChar *)elem->name;
2804
2805
4.61M
  fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2806
293k
      xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2807
4.61M
      (xmlChar *)attr->name;
2808
2809
4.61M
  if (fullelemname != NULL && fullattrname != NULL) {
2810
4.61M
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2811
4.61M
                             fullattrname);
2812
4.61M
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
2813
2.41M
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2814
2.41M
               fullattrname);
2815
4.61M
  }
2816
2817
4.61M
  if ((fullattrname != fattr) && (fullattrname != attr->name))
2818
31
      xmlFree(fullattrname);
2819
4.61M
  if ((fullelemname != felem) && (fullelemname != elem->name))
2820
136
      xmlFree(fullelemname);
2821
2822
4.61M
        if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2823
360k
      return(1);
2824
4.61M
    }
2825
4.25M
    return(0);
2826
24.1M
}
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
424k
xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2839
424k
    xmlIDTablePtr table;
2840
424k
    xmlIDPtr id;
2841
424k
    xmlChar *ID;
2842
2843
424k
    if (doc == NULL) return(-1);
2844
424k
    if (attr == NULL) return(-1);
2845
2846
424k
    table = (xmlIDTablePtr) doc->ids;
2847
424k
    if (table == NULL)
2848
414k
        return(-1);
2849
2850
10.0k
    ID = xmlNodeListGetString(doc, attr->children, 1);
2851
10.0k
    if (ID == NULL)
2852
0
        return(-1);
2853
10.0k
    xmlValidNormalizeString(ID);
2854
2855
10.0k
    id = xmlHashLookup(table, ID);
2856
10.0k
    if (id == NULL || id->attr != attr) {
2857
8.52k
        xmlFree(ID);
2858
8.52k
        return(-1);
2859
8.52k
    }
2860
2861
1.53k
    xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry);
2862
1.53k
    xmlFree(ID);
2863
1.53k
    attr->atype = 0;
2864
1.53k
    return(0);
2865
10.0k
}
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
16.6k
xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2878
16.6k
    xmlIDTablePtr table;
2879
16.6k
    xmlIDPtr id;
2880
2881
16.6k
    if (doc == NULL) {
2882
0
  return(NULL);
2883
0
    }
2884
2885
16.6k
    if (ID == NULL) {
2886
0
  return(NULL);
2887
0
    }
2888
2889
16.6k
    table = (xmlIDTablePtr) doc->ids;
2890
16.6k
    if (table == NULL)
2891
10.4k
        return(NULL);
2892
2893
6.22k
    id = xmlHashLookup(table, ID);
2894
6.22k
    if (id == NULL)
2895
900
  return(NULL);
2896
5.32k
    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
1.83k
  return((xmlAttrPtr) doc);
2902
1.83k
    }
2903
3.49k
    return(id->attr);
2904
5.32k
}
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
585k
xmlFreeRef(xmlLinkPtr lk) {
2935
585k
    xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2936
585k
    if (ref == NULL) return;
2937
585k
    if (ref->value != NULL)
2938
585k
        xmlFree((xmlChar *)ref->value);
2939
585k
    if (ref->name != NULL)
2940
23.1k
        xmlFree((xmlChar *)ref->name);
2941
585k
    xmlFree(ref);
2942
585k
}
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
224k
xmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2952
224k
    xmlListPtr list_ref = (xmlListPtr) payload;
2953
224k
    if (list_ref == NULL) return;
2954
224k
    xmlListDelete(list_ref);
2955
224k
}
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
360k
{
2989
360k
    return (0);
2990
360k
}
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
585k
    xmlAttrPtr attr) {
3008
585k
    xmlRefPtr ret;
3009
585k
    xmlRefTablePtr table;
3010
585k
    xmlListPtr ref_list;
3011
3012
585k
    if (doc == NULL) {
3013
0
        return(NULL);
3014
0
    }
3015
585k
    if (value == NULL) {
3016
0
        return(NULL);
3017
0
    }
3018
585k
    if (attr == NULL) {
3019
0
        return(NULL);
3020
0
    }
3021
3022
    /*
3023
     * Create the Ref table if needed.
3024
     */
3025
585k
    table = (xmlRefTablePtr) doc->refs;
3026
585k
    if (table == NULL) {
3027
12.5k
        doc->refs = table = xmlHashCreateDict(0, doc->dict);
3028
12.5k
    }
3029
585k
    if (table == NULL) {
3030
0
  xmlVErrMemory(ctxt,
3031
0
            "xmlAddRef: Table creation failed!\n");
3032
0
        return(NULL);
3033
0
    }
3034
3035
585k
    ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
3036
585k
    if (ret == NULL) {
3037
0
  xmlVErrMemory(ctxt, "malloc failed");
3038
0
        return(NULL);
3039
0
    }
3040
3041
    /*
3042
     * fill the structure.
3043
     */
3044
585k
    ret->value = xmlStrdup(value);
3045
585k
    if (xmlIsStreaming(ctxt)) {
3046
  /*
3047
   * Operating in streaming mode, attr is gonna disappear
3048
   */
3049
23.1k
  ret->name = xmlStrdup(attr->name);
3050
23.1k
  ret->attr = NULL;
3051
562k
    } else {
3052
562k
  ret->name = NULL;
3053
562k
  ret->attr = attr;
3054
562k
    }
3055
585k
    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
585k
    if (NULL == (ref_list = xmlHashLookup(table, value))) {
3065
224k
        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
224k
        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
224k
    }
3079
585k
    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
585k
    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
585k
}
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
12.5k
xmlFreeRefTable(xmlRefTablePtr table) {
3107
12.5k
    xmlHashFree(table, xmlFreeRefTableEntry);
3108
12.5k
}
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
23.8M
xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3126
23.8M
    if (attr == NULL)
3127
0
        return(0);
3128
23.8M
    if (doc == NULL) {
3129
0
        doc = attr->doc;
3130
0
  if (doc == NULL) return(0);
3131
0
    }
3132
3133
23.8M
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3134
19.5M
        return(0);
3135
19.5M
    } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3136
        /* TODO @@@ */
3137
0
        return(0);
3138
4.25M
    } else {
3139
4.25M
        xmlAttributePtr attrDecl;
3140
3141
4.25M
        if (elem == NULL) return(0);
3142
4.25M
        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3143
4.25M
        if ((attrDecl == NULL) && (doc->extSubset != NULL))
3144
2.07M
            attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3145
2.07M
                             elem->name, attr->name);
3146
3147
4.25M
  if ((attrDecl != NULL) &&
3148
4.25M
      (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3149
1.01M
       attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3150
525k
  return(1);
3151
4.25M
    }
3152
3.72M
    return(0);
3153
23.8M
}
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
10.5M
xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3261
10.5M
    xmlElementTablePtr table;
3262
10.5M
    xmlElementPtr cur;
3263
10.5M
    xmlChar *uqname = NULL, *prefix = NULL;
3264
3265
10.5M
    if ((dtd == NULL) || (name == NULL)) return(NULL);
3266
10.1M
    if (dtd->elements == NULL)
3267
5.60M
  return(NULL);
3268
4.53M
    table = (xmlElementTablePtr) dtd->elements;
3269
3270
4.53M
    uqname = xmlSplitQName2(name, &prefix);
3271
4.53M
    if (uqname != NULL)
3272
27.8k
        name = uqname;
3273
4.53M
    cur = xmlHashLookup2(table, name, prefix);
3274
4.53M
    if (prefix != NULL) xmlFree(prefix);
3275
4.53M
    if (uqname != NULL) xmlFree(uqname);
3276
4.53M
    return(cur);
3277
10.1M
}
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
3.81M
xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3291
3.81M
    xmlElementTablePtr table;
3292
3.81M
    xmlElementPtr cur;
3293
3.81M
    xmlChar *uqname = NULL, *prefix = NULL;
3294
3295
3.81M
    if (dtd == NULL) return(NULL);
3296
3.81M
    if (dtd->elements == NULL) {
3297
19.3k
  xmlDictPtr dict = NULL;
3298
3299
19.3k
  if (dtd->doc != NULL)
3300
19.3k
      dict = dtd->doc->dict;
3301
3302
19.3k
  if (!create)
3303
0
      return(NULL);
3304
  /*
3305
   * Create the Element table if needed.
3306
   */
3307
19.3k
  table = (xmlElementTablePtr) dtd->elements;
3308
19.3k
  if (table == NULL) {
3309
19.3k
      table = xmlHashCreateDict(0, dict);
3310
19.3k
      dtd->elements = (void *) table;
3311
19.3k
  }
3312
19.3k
  if (table == NULL) {
3313
0
      xmlVErrMemory(NULL, "element table allocation failed");
3314
0
      return(NULL);
3315
0
  }
3316
19.3k
    }
3317
3.81M
    table = (xmlElementTablePtr) dtd->elements;
3318
3319
3.81M
    uqname = xmlSplitQName2(name, &prefix);
3320
3.81M
    if (uqname != NULL)
3321
322k
        name = uqname;
3322
3.81M
    cur = xmlHashLookup2(table, name, prefix);
3323
3.81M
    if ((cur == NULL) && (create)) {
3324
37.3k
  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3325
37.3k
  if (cur == NULL) {
3326
0
      xmlVErrMemory(NULL, "malloc failed");
3327
0
      return(NULL);
3328
0
  }
3329
37.3k
  memset(cur, 0, sizeof(xmlElement));
3330
37.3k
  cur->type = XML_ELEMENT_DECL;
3331
3332
  /*
3333
   * fill the structure.
3334
   */
3335
37.3k
  cur->name = xmlStrdup(name);
3336
37.3k
  cur->prefix = xmlStrdup(prefix);
3337
37.3k
  cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3338
3339
37.3k
  xmlHashAddEntry2(table, name, prefix, cur);
3340
37.3k
    }
3341
3.81M
    if (prefix != NULL) xmlFree(prefix);
3342
3.81M
    if (uqname != NULL) xmlFree(uqname);
3343
3.81M
    return(cur);
3344
3.81M
}
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
10.0M
                const xmlChar *prefix) {
3360
10.0M
    xmlElementTablePtr table;
3361
3362
10.0M
    if (dtd == NULL) return(NULL);
3363
7.69M
    if (dtd->elements == NULL) return(NULL);
3364
2.91M
    table = (xmlElementTablePtr) dtd->elements;
3365
3366
2.91M
    return(xmlHashLookup2(table, name, prefix));
3367
7.69M
}
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
19.6M
xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3383
19.6M
    xmlAttributeTablePtr table;
3384
19.6M
    xmlAttributePtr cur;
3385
19.6M
    xmlChar *uqname = NULL, *prefix = NULL;
3386
3387
19.6M
    if (dtd == NULL) return(NULL);
3388
19.3M
    if (dtd->attributes == NULL) return(NULL);
3389
3390
7.43M
    table = (xmlAttributeTablePtr) dtd->attributes;
3391
7.43M
    if (table == NULL)
3392
0
  return(NULL);
3393
3394
7.43M
    uqname = xmlSplitQName2(name, &prefix);
3395
3396
7.43M
    if (uqname != NULL) {
3397
558k
  cur = xmlHashLookup3(table, uqname, prefix, elem);
3398
558k
  if (prefix != NULL) xmlFree(prefix);
3399
558k
  if (uqname != NULL) xmlFree(uqname);
3400
558k
    } else
3401
6.87M
  cur = xmlHashLookup3(table, name, NULL, elem);
3402
7.43M
    return(cur);
3403
7.43M
}
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
532k
            const xmlChar *prefix) {
3421
532k
    xmlAttributeTablePtr table;
3422
3423
532k
    if (dtd == NULL) return(NULL);
3424
532k
    if (dtd->attributes == NULL) return(NULL);
3425
334k
    table = (xmlAttributeTablePtr) dtd->attributes;
3426
3427
334k
    return(xmlHashLookup3(table, name, prefix, elem));
3428
532k
}
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
13.2k
xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3442
13.2k
    xmlNotationTablePtr table;
3443
3444
13.2k
    if (dtd == NULL) return(NULL);
3445
13.2k
    if (dtd->notations == NULL) return(NULL);
3446
136
    table = (xmlNotationTablePtr) dtd->notations;
3447
3448
136
    return(xmlHashLookup(table, name));
3449
13.2k
}
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
12.3k
                       const xmlChar *notationName) {
3467
12.3k
    xmlNotationPtr notaDecl;
3468
12.3k
    if ((doc == NULL) || (doc->intSubset == NULL) ||
3469
12.3k
        (notationName == NULL)) return(-1);
3470
3471
12.3k
    notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3472
12.3k
    if ((notaDecl == NULL) && (doc->extSubset != NULL))
3473
284
  notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3474
3475
12.3k
    if ((notaDecl == NULL) && (ctxt != NULL)) {
3476
12.3k
  xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3477
12.3k
                  "NOTATION %s is not declared\n",
3478
12.3k
            notationName, NULL, NULL);
3479
12.3k
  return(0);
3480
12.3k
    }
3481
48
    return(1);
3482
12.3k
}
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
6.13M
xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3498
6.13M
    xmlElementPtr elemDecl;
3499
3500
6.13M
    if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3501
3502
2.21M
    elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3503
2.21M
    if ((elemDecl == NULL) && (doc->extSubset != NULL))
3504
960k
  elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3505
2.21M
    if (elemDecl == NULL) return(-1);
3506
742k
    switch (elemDecl->etype) {
3507
945
  case XML_ELEMENT_TYPE_UNDEFINED:
3508
945
      return(-1);
3509
717k
  case XML_ELEMENT_TYPE_ELEMENT:
3510
717k
      return(0);
3511
410
        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
431
  case XML_ELEMENT_TYPE_ANY:
3517
24.2k
  case XML_ELEMENT_TYPE_MIXED:
3518
24.2k
      return(1);
3519
742k
    }
3520
0
    return(1);
3521
742k
}
3522
3523
#ifdef LIBXML_VALID_ENABLED
3524
3525
static int
3526
187k
xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3527
187k
    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
75.0k
  if (((c >= 'a') && (c <= 'z')) ||
3533
75.0k
      ((c >= 'A') && (c <= 'Z')) ||
3534
75.0k
      (c == '_') || (c == ':') ||
3535
75.0k
      ((c >= 0xC0) && (c <= 0xD6)) ||
3536
75.0k
      ((c >= 0xD8) && (c <= 0xF6)) ||
3537
75.0k
      ((c >= 0xF8) && (c <= 0x2FF)) ||
3538
75.0k
      ((c >= 0x370) && (c <= 0x37D)) ||
3539
75.0k
      ((c >= 0x37F) && (c <= 0x1FFF)) ||
3540
75.0k
      ((c >= 0x200C) && (c <= 0x200D)) ||
3541
75.0k
      ((c >= 0x2070) && (c <= 0x218F)) ||
3542
75.0k
      ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3543
75.0k
      ((c >= 0x3001) && (c <= 0xD7FF)) ||
3544
75.0k
      ((c >= 0xF900) && (c <= 0xFDCF)) ||
3545
75.0k
      ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3546
75.0k
      ((c >= 0x10000) && (c <= 0xEFFFF)))
3547
66.1k
      return(1);
3548
112k
    } else {
3549
112k
        if (IS_LETTER(c) || (c == '_') || (c == ':'))
3550
108k
      return(1);
3551
112k
    }
3552
12.7k
    return(0);
3553
187k
}
3554
3555
static int
3556
2.52M
xmlIsDocNameChar(xmlDocPtr doc, int c) {
3557
2.52M
    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
1.16M
  if (((c >= 'a') && (c <= 'z')) ||
3563
1.16M
      ((c >= 'A') && (c <= 'Z')) ||
3564
1.16M
      ((c >= '0') && (c <= '9')) || /* !start */
3565
1.16M
      (c == '_') || (c == ':') ||
3566
1.16M
      (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3567
1.16M
      ((c >= 0xC0) && (c <= 0xD6)) ||
3568
1.16M
      ((c >= 0xD8) && (c <= 0xF6)) ||
3569
1.16M
      ((c >= 0xF8) && (c <= 0x2FF)) ||
3570
1.16M
      ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3571
1.16M
      ((c >= 0x370) && (c <= 0x37D)) ||
3572
1.16M
      ((c >= 0x37F) && (c <= 0x1FFF)) ||
3573
1.16M
      ((c >= 0x200C) && (c <= 0x200D)) ||
3574
1.16M
      ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3575
1.16M
      ((c >= 0x2070) && (c <= 0x218F)) ||
3576
1.16M
      ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3577
1.16M
      ((c >= 0x3001) && (c <= 0xD7FF)) ||
3578
1.16M
      ((c >= 0xF900) && (c <= 0xFDCF)) ||
3579
1.16M
      ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3580
1.16M
      ((c >= 0x10000) && (c <= 0xEFFFF)))
3581
949k
       return(1);
3582
1.35M
    } else {
3583
1.35M
        if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3584
1.35M
            (c == '.') || (c == '-') ||
3585
1.35M
      (c == '_') || (c == ':') ||
3586
1.35M
      (IS_COMBINING(c)) ||
3587
1.35M
      (IS_EXTENDER(c)))
3588
1.15M
      return(1);
3589
1.35M
    }
3590
418k
    return(0);
3591
2.52M
}
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
160k
xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3605
160k
    const xmlChar *cur;
3606
160k
    int val, len;
3607
3608
160k
    if (value == NULL) return(0);
3609
160k
    cur = value;
3610
160k
    val = xmlStringCurrentChar(NULL, cur, &len);
3611
160k
    cur += len;
3612
160k
    if (!xmlIsDocNameStartChar(doc, val))
3613
8.10k
  return(0);
3614
3615
152k
    val = xmlStringCurrentChar(NULL, cur, &len);
3616
152k
    cur += len;
3617
1.23M
    while (xmlIsDocNameChar(doc, val)) {
3618
1.08M
  val = xmlStringCurrentChar(NULL, cur, &len);
3619
1.08M
  cur += len;
3620
1.08M
    }
3621
3622
152k
    if (val != 0) return(0);
3623
3624
151k
    return(1);
3625
152k
}
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
12.7k
xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3653
12.7k
    const xmlChar *cur;
3654
12.7k
    int val, len;
3655
3656
12.7k
    if (value == NULL) return(0);
3657
12.7k
    cur = value;
3658
12.7k
    val = xmlStringCurrentChar(NULL, cur, &len);
3659
12.7k
    cur += len;
3660
3661
12.7k
    if (!xmlIsDocNameStartChar(doc, val))
3662
382
  return(0);
3663
3664
12.3k
    val = xmlStringCurrentChar(NULL, cur, &len);
3665
12.3k
    cur += len;
3666
77.4k
    while (xmlIsDocNameChar(doc, val)) {
3667
65.0k
  val = xmlStringCurrentChar(NULL, cur, &len);
3668
65.0k
  cur += len;
3669
65.0k
    }
3670
3671
    /* Should not test IS_BLANK(val) here -- see erratum E20*/
3672
22.2k
    while (val == 0x20) {
3673
28.8k
  while (val == 0x20) {
3674
14.7k
      val = xmlStringCurrentChar(NULL, cur, &len);
3675
14.7k
      cur += len;
3676
14.7k
  }
3677
3678
14.0k
  if (!xmlIsDocNameStartChar(doc, val))
3679
4.26k
      return(0);
3680
3681
9.82k
  val = xmlStringCurrentChar(NULL, cur, &len);
3682
9.82k
  cur += len;
3683
3684
58.0k
  while (xmlIsDocNameChar(doc, val)) {
3685
48.2k
      val = xmlStringCurrentChar(NULL, cur, &len);
3686
48.2k
      cur += len;
3687
48.2k
  }
3688
9.82k
    }
3689
3690
8.13k
    if (val != 0) return(0);
3691
3692
7.40k
    return(1);
3693
8.13k
}
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
99.2k
xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3723
99.2k
    const xmlChar *cur;
3724
99.2k
    int val, len;
3725
3726
99.2k
    if (value == NULL) return(0);
3727
99.2k
    cur = value;
3728
99.2k
    val = xmlStringCurrentChar(NULL, cur, &len);
3729
99.2k
    cur += len;
3730
3731
99.2k
    if (!xmlIsDocNameChar(doc, val))
3732
7.42k
  return(0);
3733
3734
91.8k
    val = xmlStringCurrentChar(NULL, cur, &len);
3735
91.8k
    cur += len;
3736
162k
    while (xmlIsDocNameChar(doc, val)) {
3737
70.6k
  val = xmlStringCurrentChar(NULL, cur, &len);
3738
70.6k
  cur += len;
3739
70.6k
    }
3740
3741
91.8k
    if (val != 0) return(0);
3742
3743
90.9k
    return(1);
3744
91.8k
}
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
111k
xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3776
111k
    const xmlChar *cur;
3777
111k
    int val, len;
3778
3779
111k
    if (value == NULL) return(0);
3780
111k
    cur = value;
3781
111k
    val = xmlStringCurrentChar(NULL, cur, &len);
3782
111k
    cur += len;
3783
3784
111k
    while (IS_BLANK(val)) {
3785
5.88k
  val = xmlStringCurrentChar(NULL, cur, &len);
3786
5.88k
  cur += len;
3787
5.88k
    }
3788
3789
111k
    if (!xmlIsDocNameChar(doc, val))
3790
4.39k
  return(0);
3791
3792
602k
    while (xmlIsDocNameChar(doc, val)) {
3793
494k
  val = xmlStringCurrentChar(NULL, cur, &len);
3794
494k
  cur += len;
3795
494k
    }
3796
3797
    /* Should not test IS_BLANK(val) here -- see erratum E20*/
3798
137k
    while (val == 0x20) {
3799
66.3k
  while (val == 0x20) {
3800
33.1k
      val = xmlStringCurrentChar(NULL, cur, &len);
3801
33.1k
      cur += len;
3802
33.1k
  }
3803
33.1k
  if (val == 0) return(1);
3804
3805
32.9k
  if (!xmlIsDocNameChar(doc, val))
3806
2.19k
      return(0);
3807
3808
30.7k
  val = xmlStringCurrentChar(NULL, cur, &len);
3809
30.7k
  cur += len;
3810
3811
137k
  while (xmlIsDocNameChar(doc, val)) {
3812
106k
      val = xmlStringCurrentChar(NULL, cur, &len);
3813
106k
      cur += len;
3814
106k
  }
3815
30.7k
    }
3816
3817
104k
    if (val != 0) return(0);
3818
3819
98.8k
    return(1);
3820
104k
}
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
1.03k
                         xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3856
1.03k
    int ret = 1;
3857
3858
1.03k
    return(ret);
3859
1.03k
}
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
1.05M
                                  const xmlChar *value) {
3875
1.05M
    switch (type) {
3876
562
  case XML_ATTRIBUTE_ENTITIES:
3877
12.7k
  case XML_ATTRIBUTE_IDREFS:
3878
12.7k
      return(xmlValidateNamesValueInternal(doc, value));
3879
131
  case XML_ATTRIBUTE_ENTITY:
3880
72.1k
  case XML_ATTRIBUTE_IDREF:
3881
160k
  case XML_ATTRIBUTE_ID:
3882
160k
  case XML_ATTRIBUTE_NOTATION:
3883
160k
      return(xmlValidateNameValueInternal(doc, value));
3884
41.0k
  case XML_ATTRIBUTE_NMTOKENS:
3885
111k
  case XML_ATTRIBUTE_ENUMERATION:
3886
111k
      return(xmlValidateNmtokensValueInternal(doc, value));
3887
99.2k
  case XML_ATTRIBUTE_NMTOKEN:
3888
99.2k
      return(xmlValidateNmtokenValueInternal(doc, value));
3889
672k
        case XML_ATTRIBUTE_CDATA:
3890
672k
      break;
3891
1.05M
    }
3892
672k
    return(1);
3893
1.05M
}
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
494k
      const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3956
494k
    int ret = 1;
3957
494k
    switch (type) {
3958
1.83k
  case XML_ATTRIBUTE_IDREFS:
3959
59.9k
  case XML_ATTRIBUTE_IDREF:
3960
146k
  case XML_ATTRIBUTE_ID:
3961
166k
  case XML_ATTRIBUTE_NMTOKENS:
3962
181k
  case XML_ATTRIBUTE_ENUMERATION:
3963
213k
  case XML_ATTRIBUTE_NMTOKEN:
3964
493k
        case XML_ATTRIBUTE_CDATA:
3965
493k
      break;
3966
34
  case XML_ATTRIBUTE_ENTITY: {
3967
34
      xmlEntityPtr ent;
3968
3969
34
      ent = xmlGetDocEntity(doc, value);
3970
      /* yeah it's a bit messy... */
3971
34
      if ((ent == NULL) && (doc->standalone == 1)) {
3972
0
    doc->standalone = 0;
3973
0
    ent = xmlGetDocEntity(doc, value);
3974
0
      }
3975
34
      if (ent == NULL) {
3976
34
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3977
34
        XML_DTD_UNKNOWN_ENTITY,
3978
34
   "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3979
34
           name, value, NULL);
3980
34
    ret = 0;
3981
34
      } 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
34
      break;
3989
213k
        }
3990
160
  case XML_ATTRIBUTE_ENTITIES: {
3991
160
      xmlChar *dup, *nam = NULL, *cur, save;
3992
160
      xmlEntityPtr ent;
3993
3994
160
      dup = xmlStrdup(value);
3995
160
      if (dup == NULL)
3996
0
    return(0);
3997
160
      cur = dup;
3998
437
      while (*cur != 0) {
3999
433
    nam = cur;
4000
4.57k
    while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
4001
433
    save = *cur;
4002
433
    *cur = 0;
4003
433
    ent = xmlGetDocEntity(doc, nam);
4004
433
    if (ent == NULL) {
4005
423
        xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4006
423
            XML_DTD_UNKNOWN_ENTITY,
4007
423
       "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
4008
423
         name, nam, NULL);
4009
423
        ret = 0;
4010
423
    } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4011
10
        xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4012
10
            XML_DTD_ENTITY_TYPE,
4013
10
       "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
4014
10
         name, nam, NULL);
4015
10
        ret = 0;
4016
10
    }
4017
433
    if (save == 0)
4018
156
        break;
4019
277
    *cur = save;
4020
293
    while (IS_BLANK_CH(*cur)) cur++;
4021
277
      }
4022
160
      xmlFree(dup);
4023
160
      break;
4024
160
  }
4025
419
  case XML_ATTRIBUTE_NOTATION: {
4026
419
      xmlNotationPtr nota;
4027
4028
419
      nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4029
419
      if ((nota == NULL) && (doc->extSubset != NULL))
4030
168
    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4031
4032
419
      if (nota == NULL) {
4033
400
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4034
400
                    XML_DTD_UNKNOWN_NOTATION,
4035
400
       "NOTATION attribute %s reference an unknown notation \"%s\"\n",
4036
400
           name, value, NULL);
4037
400
    ret = 0;
4038
400
      }
4039
419
      break;
4040
160
        }
4041
494k
    }
4042
494k
    return(ret);
4043
494k
}
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
9.67M
       xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4072
9.67M
    xmlChar *ret;
4073
9.67M
    xmlAttributePtr attrDecl = NULL;
4074
9.67M
    int extsubset = 0;
4075
4076
9.67M
    if (doc == NULL) return(NULL);
4077
9.67M
    if (elem == NULL) return(NULL);
4078
9.67M
    if (name == NULL) return(NULL);
4079
9.67M
    if (value == NULL) return(NULL);
4080
4081
9.67M
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4082
442k
  xmlChar fn[50];
4083
442k
  xmlChar *fullname;
4084
4085
442k
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4086
442k
  if (fullname == NULL)
4087
0
      return(NULL);
4088
442k
  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4089
442k
  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4090
157
      attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4091
157
      if (attrDecl != NULL)
4092
0
    extsubset = 1;
4093
157
  }
4094
442k
  if ((fullname != fn) && (fullname != elem->name))
4095
313
      xmlFree(fullname);
4096
442k
    }
4097
9.67M
    if ((attrDecl == NULL) && (doc->intSubset != NULL))
4098
2.40M
  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4099
9.67M
    if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4100
1.26M
  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4101
1.26M
  if (attrDecl != NULL)
4102
582k
      extsubset = 1;
4103
1.26M
    }
4104
4105
9.67M
    if (attrDecl == NULL)
4106
8.90M
  return(NULL);
4107
767k
    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4108
295k
  return(NULL);
4109
4110
472k
    ret = xmlStrdup(value);
4111
472k
    if (ret == NULL)
4112
0
  return(NULL);
4113
472k
    xmlValidNormalizeString(ret);
4114
472k
    if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4115
66
  xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4116
66
"standalone: %s on %s value had to be normalized based on external subset declaration\n",
4117
66
         name, elem->name, NULL);
4118
66
  ctxt->valid = 0;
4119
66
    }
4120
472k
    return(ret);
4121
472k
}
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
450k
              const xmlChar *name, const xmlChar *value) {
4145
450k
    xmlChar *ret;
4146
450k
    xmlAttributePtr attrDecl = NULL;
4147
4148
450k
    if (doc == NULL) return(NULL);
4149
450k
    if (elem == NULL) return(NULL);
4150
450k
    if (name == NULL) return(NULL);
4151
450k
    if (value == NULL) return(NULL);
4152
4153
450k
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4154
32.5k
  xmlChar fn[50];
4155
32.5k
  xmlChar *fullname;
4156
4157
32.5k
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4158
32.5k
  if (fullname == NULL)
4159
0
      return(NULL);
4160
32.5k
  if ((fullname != fn) && (fullname != elem->name))
4161
6
      xmlFree(fullname);
4162
32.5k
    }
4163
450k
    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4164
450k
    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4165
208k
  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4166
4167
450k
    if (attrDecl == NULL)
4168
362k
  return(NULL);
4169
88.3k
    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4170
29.6k
  return(NULL);
4171
4172
58.7k
    ret = xmlStrdup(value);
4173
58.7k
    if (ret == NULL)
4174
0
  return(NULL);
4175
58.7k
    xmlValidNormalizeString(ret);
4176
58.7k
    return(ret);
4177
58.7k
}
4178
4179
static void
4180
xmlValidateAttributeIdCallback(void *payload, void *data,
4181
118
                         const xmlChar *name ATTRIBUTE_UNUSED) {
4182
118
    xmlAttributePtr attr = (xmlAttributePtr) payload;
4183
118
    int *count = (int *) data;
4184
118
    if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4185
118
}
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
2.42M
                         xmlAttributePtr attr) {
4208
2.42M
    int ret = 1;
4209
2.42M
    int val;
4210
2.42M
    CHECK_DTD;
4211
2.42M
    if(attr == NULL) return(1);
4212
4213
    /* Attribute Default Legal */
4214
    /* Enumeration */
4215
2.42M
    if (attr->defaultValue != NULL) {
4216
185k
  val = xmlValidateAttributeValueInternal(doc, attr->atype,
4217
185k
                                          attr->defaultValue);
4218
185k
  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
185k
        ret &= val;
4224
185k
    }
4225
4226
    /* ID Attribute Default */
4227
2.42M
    if ((attr->atype == XML_ATTRIBUTE_ID)&&
4228
2.42M
        (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4229
2.42M
  (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4230
194
  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4231
194
          "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4232
194
         attr->name, attr->elem, NULL);
4233
194
  ret = 0;
4234
194
    }
4235
4236
    /* One ID per Element Type */
4237
2.42M
    if (attr->atype == XML_ATTRIBUTE_ID) {
4238
720k
        int nbId;
4239
4240
  /* the trick is that we parse DtD as their own internal subset */
4241
720k
        xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4242
720k
                                            attr->elem);
4243
720k
  if (elem != NULL) {
4244
161k
      nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4245
559k
  } else {
4246
559k
      xmlAttributeTablePtr table;
4247
4248
      /*
4249
       * The attribute may be declared in the internal subset and the
4250
       * element in the external subset.
4251
       */
4252
559k
      nbId = 0;
4253
559k
      if (doc->intSubset != NULL) {
4254
559k
    table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4255
559k
    xmlHashScan3(table, NULL, NULL, attr->elem,
4256
559k
           xmlValidateAttributeIdCallback, &nbId);
4257
559k
      }
4258
559k
  }
4259
720k
  if (nbId > 1) {
4260
4261
168
      xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4262
168
       "Element %s has %d ID attribute defined in the internal subset : %s\n",
4263
168
       attr->elem, nbId, attr->name);
4264
720k
  } else if (doc->extSubset != NULL) {
4265
559k
      int extId = 0;
4266
559k
      elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4267
559k
      if (elem != NULL) {
4268
559k
    extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4269
559k
      }
4270
559k
      if (extId > 1) {
4271
118
    xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4272
118
       "Element %s has %d ID attribute defined in the external subset : %s\n",
4273
118
           attr->elem, extId, attr->name);
4274
559k
      } else if (extId + nbId > 1) {
4275
36
    xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4276
36
"Element %s has ID attributes defined in the internal and external subset : %s\n",
4277
36
           attr->elem, attr->name, NULL);
4278
36
      }
4279
559k
  }
4280
720k
    }
4281
4282
    /* Validity Constraint: Enumeration */
4283
2.42M
    if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4284
20.6k
        xmlEnumerationPtr tree = attr->tree;
4285
35.8k
  while (tree != NULL) {
4286
35.1k
      if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4287
15.2k
      tree = tree->next;
4288
15.2k
  }
4289
20.6k
  if (tree == NULL) {
4290
716
      xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4291
716
"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4292
716
       attr->defaultValue, attr->name, attr->elem);
4293
716
      ret = 0;
4294
716
  }
4295
20.6k
    }
4296
4297
2.42M
    return(ret);
4298
2.42M
}
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
1.05M
                       xmlElementPtr elem) {
4319
1.05M
    int ret = 1;
4320
1.05M
    xmlElementPtr tst;
4321
4322
1.05M
    CHECK_DTD;
4323
4324
1.05M
    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
1.05M
    if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4335
376k
  xmlElementContentPtr cur, next;
4336
376k
        const xmlChar *name;
4337
4338
376k
  cur = elem->content;
4339
1.97M
  while (cur != NULL) {
4340
1.97M
      if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4341
1.59M
      if (cur->c1 == NULL) break;
4342
1.59M
      if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4343
1.44M
    name = cur->c1->name;
4344
1.44M
    next = cur->c2;
4345
14.5M
    while (next != NULL) {
4346
14.5M
        if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4347
1.44M
            if ((xmlStrEqual(next->name, name)) &&
4348
1.44M
          (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4349
812
          if (cur->c1->prefix == NULL) {
4350
531
        xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4351
531
       "Definition of %s has duplicate references of %s\n",
4352
531
               elem->name, name, NULL);
4353
531
          } else {
4354
281
        xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4355
281
       "Definition of %s has duplicate references of %s:%s\n",
4356
281
               elem->name, cur->c1->prefix, name);
4357
281
          }
4358
812
          ret = 0;
4359
812
      }
4360
1.44M
      break;
4361
1.44M
        }
4362
13.0M
        if (next->c1 == NULL) break;
4363
13.0M
        if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4364
13.0M
        if ((xmlStrEqual(next->c1->name, name)) &&
4365
13.0M
            (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4366
1.22k
      if (cur->c1->prefix == NULL) {
4367
586
          xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4368
586
         "Definition of %s has duplicate references to %s\n",
4369
586
           elem->name, name, NULL);
4370
639
      } else {
4371
639
          xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4372
639
         "Definition of %s has duplicate references to %s:%s\n",
4373
639
           elem->name, cur->c1->prefix, name);
4374
639
      }
4375
1.22k
      ret = 0;
4376
1.22k
        }
4377
13.0M
        next = next->c2;
4378
13.0M
    }
4379
1.44M
      }
4380
1.59M
      cur = cur->c2;
4381
1.59M
  }
4382
376k
    }
4383
4384
    /* VC: Unique Element Type Declaration */
4385
1.05M
    tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4386
1.05M
    if ((tst != NULL ) && (tst != elem) &&
4387
1.05M
  ((tst->prefix == elem->prefix) ||
4388
361
   (xmlStrEqual(tst->prefix, elem->prefix))) &&
4389
1.05M
  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4390
117
  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4391
117
                  "Redefinition of element %s\n",
4392
117
           elem->name, NULL, NULL);
4393
117
  ret = 0;
4394
117
    }
4395
1.05M
    tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4396
1.05M
    if ((tst != NULL ) && (tst != elem) &&
4397
1.05M
  ((tst->prefix == elem->prefix) ||
4398
230
   (xmlStrEqual(tst->prefix, elem->prefix))) &&
4399
1.05M
  (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
1.05M
    return(ret);
4411
1.05M
}
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.25M
{
4442
1.25M
    xmlAttributePtr attrDecl =  NULL;
4443
1.25M
    int val;
4444
1.25M
    int ret = 1;
4445
4446
1.25M
    CHECK_DTD;
4447
1.25M
    if ((elem == NULL) || (elem->name == NULL)) return(0);
4448
1.25M
    if ((attr == NULL) || (attr->name == NULL)) return(0);
4449
4450
1.25M
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4451
216k
  xmlChar fn[50];
4452
216k
  xmlChar *fullname;
4453
4454
216k
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4455
216k
  if (fullname == NULL)
4456
0
      return(0);
4457
216k
  if (attr->ns != NULL) {
4458
211k
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4459
211k
                              attr->name, attr->ns->prefix);
4460
211k
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4461
0
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4462
0
                attr->name, attr->ns->prefix);
4463
211k
  } else {
4464
5.04k
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4465
5.04k
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4466
109
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4467
109
               fullname, attr->name);
4468
5.04k
  }
4469
216k
  if ((fullname != fn) && (fullname != elem->name))
4470
33
      xmlFree(fullname);
4471
216k
    }
4472
1.25M
    if (attrDecl == NULL) {
4473
1.05M
  if (attr->ns != NULL) {
4474
37.8k
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4475
37.8k
                              attr->name, attr->ns->prefix);
4476
37.8k
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4477
19.5k
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4478
19.5k
                attr->name, attr->ns->prefix);
4479
1.01M
  } else {
4480
1.01M
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4481
1.01M
                             elem->name, attr->name);
4482
1.01M
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4483
500k
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4484
500k
               elem->name, attr->name);
4485
1.01M
  }
4486
1.05M
    }
4487
4488
4489
    /* Validity Constraint: Attribute Value Type */
4490
1.25M
    if (attrDecl == NULL) {
4491
770k
  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4492
770k
         "No declaration for attribute %s of element %s\n",
4493
770k
         attr->name, elem->name, NULL);
4494
770k
  return(0);
4495
770k
    }
4496
481k
    attr->atype = attrDecl->atype;
4497
4498
481k
    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4499
481k
    if (val == 0) {
4500
12.5k
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4501
12.5k
     "Syntax of value for attribute %s of %s is not valid\n",
4502
12.5k
         attr->name, elem->name, NULL);
4503
12.5k
        ret = 0;
4504
12.5k
    }
4505
4506
    /* Validity constraint: Fixed Attribute Default */
4507
481k
    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4508
57.3k
  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4509
27
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4510
27
     "Value for attribute %s of %s is different from default \"%s\"\n",
4511
27
       attr->name, elem->name, attrDecl->defaultValue);
4512
27
      ret = 0;
4513
27
  }
4514
57.3k
    }
4515
4516
    /* Validity Constraint: ID uniqueness */
4517
481k
    if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4518
86.1k
        if (xmlAddID(ctxt, doc, value, attr) == NULL)
4519
7.58k
      ret = 0;
4520
86.1k
    }
4521
4522
481k
    if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4523
481k
  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4524
59.9k
        if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4525
0
      ret = 0;
4526
59.9k
    }
4527
4528
    /* Validity Constraint: Notation Attributes */
4529
481k
    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4530
12
        xmlEnumerationPtr tree = attrDecl->tree;
4531
12
        xmlNotationPtr nota;
4532
4533
        /* First check that the given NOTATION was declared */
4534
12
  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4535
12
  if (nota == NULL)
4536
12
      nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4537
4538
12
  if (nota == NULL) {
4539
12
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4540
12
       "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4541
12
       value, attr->name, elem->name);
4542
12
      ret = 0;
4543
12
        }
4544
4545
  /* Second, verify that it's among the list */
4546
15
  while (tree != NULL) {
4547
12
      if (xmlStrEqual(tree->name, value)) break;
4548
3
      tree = tree->next;
4549
3
  }
4550
12
  if (tree == NULL) {
4551
3
      xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4552
3
"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4553
3
       value, attr->name, elem->name);
4554
3
      ret = 0;
4555
3
  }
4556
12
    }
4557
4558
    /* Validity Constraint: Enumeration */
4559
481k
    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4560
14.9k
        xmlEnumerationPtr tree = attrDecl->tree;
4561
24.0k
  while (tree != NULL) {
4562
23.5k
      if (xmlStrEqual(tree->name, value)) break;
4563
9.10k
      tree = tree->next;
4564
9.10k
  }
4565
14.9k
  if (tree == NULL) {
4566
482
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4567
482
       "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4568
482
       value, attr->name, elem->name);
4569
482
      ret = 0;
4570
482
  }
4571
14.9k
    }
4572
4573
    /* Fixed Attribute Default */
4574
481k
    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4575
481k
        (!xmlStrEqual(attrDecl->defaultValue, value))) {
4576
27
  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4577
27
     "Value for attribute %s of %s must be \"%s\"\n",
4578
27
         attr->name, elem->name, attrDecl->defaultValue);
4579
27
        ret = 0;
4580
27
    }
4581
4582
    /* Extra check for the attribute value */
4583
481k
    ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4584
481k
              attrDecl->atype, value);
4585
4586
481k
    return(ret);
4587
1.25M
}
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
18.7k
xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4618
    /* xmlElementPtr elemDecl; */
4619
18.7k
    xmlAttributePtr attrDecl =  NULL;
4620
18.7k
    int val;
4621
18.7k
    int ret = 1;
4622
4623
18.7k
    CHECK_DTD;
4624
18.7k
    if ((elem == NULL) || (elem->name == NULL)) return(0);
4625
18.7k
    if ((ns == NULL) || (ns->href == NULL)) return(0);
4626
4627
18.4k
    if (prefix != NULL) {
4628
15.6k
  xmlChar fn[50];
4629
15.6k
  xmlChar *fullname;
4630
4631
15.6k
  fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4632
15.6k
  if (fullname == NULL) {
4633
0
      xmlVErrMemory(ctxt, "Validating namespace");
4634
0
      return(0);
4635
0
  }
4636
15.6k
  if (ns->prefix != NULL) {
4637
15.5k
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4638
15.5k
                              ns->prefix, BAD_CAST "xmlns");
4639
15.5k
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4640
1.02k
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4641
1.02k
            ns->prefix, BAD_CAST "xmlns");
4642
15.5k
  } else {
4643
140
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4644
140
                             BAD_CAST "xmlns");
4645
140
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4646
29
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4647
29
                       BAD_CAST "xmlns");
4648
140
  }
4649
15.6k
  if ((fullname != fn) && (fullname != elem->name))
4650
98
      xmlFree(fullname);
4651
15.6k
    }
4652
18.4k
    if (attrDecl == NULL) {
4653
8.70k
  if (ns->prefix != NULL) {
4654
7.59k
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4655
7.59k
                              ns->prefix, BAD_CAST "xmlns");
4656
7.59k
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4657
1.12k
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4658
1.12k
                ns->prefix, BAD_CAST "xmlns");
4659
7.59k
  } else {
4660
1.10k
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4661
1.10k
                             elem->name, BAD_CAST "xmlns");
4662
1.10k
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4663
34
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4664
34
               elem->name, BAD_CAST "xmlns");
4665
1.10k
  }
4666
8.70k
    }
4667
4668
4669
    /* Validity Constraint: Attribute Value Type */
4670
18.4k
    if (attrDecl == NULL) {
4671
5.67k
  if (ns->prefix != NULL) {
4672
5.37k
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4673
5.37k
       "No declaration for attribute xmlns:%s of element %s\n",
4674
5.37k
       ns->prefix, elem->name, NULL);
4675
5.37k
  } else {
4676
293
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4677
293
       "No declaration for attribute xmlns of element %s\n",
4678
293
       elem->name, NULL, NULL);
4679
293
  }
4680
5.67k
  return(0);
4681
5.67k
    }
4682
4683
12.8k
    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4684
12.8k
    if (val == 0) {
4685
24
  if (ns->prefix != NULL) {
4686
24
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4687
24
         "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4688
24
       ns->prefix, elem->name, NULL);
4689
24
  } else {
4690
0
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4691
0
         "Syntax of value for attribute xmlns of %s is not valid\n",
4692
0
       elem->name, NULL, NULL);
4693
0
  }
4694
24
        ret = 0;
4695
24
    }
4696
4697
    /* Validity constraint: Fixed Attribute Default */
4698
12.8k
    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4699
10.3k
  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4700
748
      if (ns->prefix != NULL) {
4701
397
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4702
397
       "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4703
397
           ns->prefix, elem->name, attrDecl->defaultValue);
4704
397
      } else {
4705
351
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4706
351
       "Value for attribute xmlns of %s is different from default \"%s\"\n",
4707
351
           elem->name, attrDecl->defaultValue, NULL);
4708
351
      }
4709
748
      ret = 0;
4710
748
  }
4711
10.3k
    }
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
12.8k
    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
12.8k
    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4776
234
        xmlEnumerationPtr tree = attrDecl->tree;
4777
432
  while (tree != NULL) {
4778
339
      if (xmlStrEqual(tree->name, value)) break;
4779
198
      tree = tree->next;
4780
198
  }
4781
234
  if (tree == NULL) {
4782
93
      if (ns->prefix != NULL) {
4783
90
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4784
90
"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4785
90
           value, ns->prefix, elem->name);
4786
90
      } else {
4787
3
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4788
3
"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4789
3
           value, elem->name, NULL);
4790
3
      }
4791
93
      ret = 0;
4792
93
  }
4793
234
    }
4794
4795
    /* Fixed Attribute Default */
4796
12.8k
    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4797
12.8k
        (!xmlStrEqual(attrDecl->defaultValue, value))) {
4798
748
  if (ns->prefix != NULL) {
4799
397
      xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4800
397
       "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4801
397
       ns->prefix, elem->name, attrDecl->defaultValue);
4802
397
  } else {
4803
351
      xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4804
351
       "Value for attribute xmlns of %s must be \"%s\"\n",
4805
351
       elem->name, attrDecl->defaultValue, NULL);
4806
351
  }
4807
748
        ret = 0;
4808
748
    }
4809
4810
    /* Extra check for the attribute value */
4811
12.8k
    if (ns->prefix != NULL) {
4812
11.9k
  ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4813
11.9k
            attrDecl->atype, value);
4814
11.9k
    } else {
4815
816
  ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4816
816
            attrDecl->atype, value);
4817
816
    }
4818
4819
12.8k
    return(ret);
4820
18.4k
}
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
13.4k
xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5242
13.4k
    xmlNodePtr cur;
5243
13.4k
    int len;
5244
5245
13.4k
    if (node == NULL) return;
5246
12.6k
    if (glob) strcat(buf, "(");
5247
12.6k
    cur = node;
5248
69.5k
    while (cur != NULL) {
5249
56.9k
  len = strlen(buf);
5250
56.9k
  if (size - len < 50) {
5251
0
      if ((size - len > 4) && (buf[len - 1] != '.'))
5252
0
    strcat(buf, " ...");
5253
0
      return;
5254
0
  }
5255
56.9k
        switch (cur->type) {
5256
25.2k
            case XML_ELEMENT_NODE:
5257
25.2k
    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5258
12.3k
        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
12.3k
        strcat(buf, (char *) cur->ns->prefix);
5264
12.3k
        strcat(buf, ":");
5265
12.3k
    }
5266
25.2k
                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
25.2k
          strcat(buf, (char *) cur->name);
5272
25.2k
    if (cur->next != NULL)
5273
21.9k
        strcat(buf, " ");
5274
25.2k
    break;
5275
27.8k
            case XML_TEXT_NODE:
5276
27.8k
    if (xmlIsBlankNode(cur))
5277
24.0k
        break;
5278
                /* Falls through. */
5279
3.99k
            case XML_CDATA_SECTION_NODE:
5280
5.46k
            case XML_ENTITY_REF_NODE:
5281
5.46k
          strcat(buf, "CDATA");
5282
5.46k
    if (cur->next != NULL)
5283
3.42k
        strcat(buf, " ");
5284
5.46k
    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
108
            case XML_PI_NODE:
5298
108
            case XML_DTD_NODE:
5299
2.14k
            case XML_COMMENT_NODE:
5300
2.14k
      case XML_ELEMENT_DECL:
5301
2.14k
      case XML_ATTRIBUTE_DECL:
5302
2.14k
      case XML_ENTITY_DECL:
5303
2.14k
      case XML_XINCLUDE_START:
5304
2.14k
      case XML_XINCLUDE_END:
5305
2.14k
    break;
5306
56.9k
  }
5307
56.9k
  cur = cur->next;
5308
56.9k
    }
5309
12.6k
    if (glob) strcat(buf, ")");
5310
12.6k
}
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
219k
       xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5328
219k
    int ret = 1;
5329
#ifndef  LIBXML_REGEXP_ENABLED
5330
    xmlNodePtr repl = NULL, last = NULL, tmp;
5331
#endif
5332
219k
    xmlNodePtr cur;
5333
219k
    xmlElementContentPtr cont;
5334
219k
    const xmlChar *name;
5335
5336
219k
    if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
5337
0
  return(-1);
5338
219k
    cont = elemDecl->content;
5339
219k
    name = elemDecl->name;
5340
5341
219k
#ifdef LIBXML_REGEXP_ENABLED
5342
    /* Build the regexp associated to the content model */
5343
219k
    if (elemDecl->contModel == NULL)
5344
70.4k
  ret = xmlValidBuildContentModel(ctxt, elemDecl);
5345
219k
    if (elemDecl->contModel == NULL) {
5346
0
  return(-1);
5347
219k
    } else {
5348
219k
  xmlRegExecCtxtPtr exec;
5349
5350
219k
  if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5351
504
      return(-1);
5352
504
  }
5353
218k
  ctxt->nodeMax = 0;
5354
218k
  ctxt->nodeNr = 0;
5355
218k
  ctxt->nodeTab = NULL;
5356
218k
  exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5357
218k
  if (exec != NULL) {
5358
218k
      cur = child;
5359
1.16M
      while (cur != NULL) {
5360
952k
    switch (cur->type) {
5361
1.89k
        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.89k
      if ((cur->children != NULL) &&
5367
1.89k
          (cur->children->children != NULL)) {
5368
883
          nodeVPush(ctxt, cur);
5369
883
          cur = cur->children->children;
5370
883
          continue;
5371
883
      }
5372
1.01k
      break;
5373
425k
        case XML_TEXT_NODE:
5374
425k
      if (xmlIsBlankNode(cur))
5375
421k
          break;
5376
3.51k
      ret = 0;
5377
3.51k
      goto fail;
5378
217
        case XML_CDATA_SECTION_NODE:
5379
      /* TODO */
5380
217
      ret = 0;
5381
217
      goto fail;
5382
509k
        case XML_ELEMENT_NODE:
5383
509k
      if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5384
102k
          xmlChar fn[50];
5385
102k
          xmlChar *fullname;
5386
5387
102k
          fullname = xmlBuildQName(cur->name,
5388
102k
                             cur->ns->prefix, fn, 50);
5389
102k
          if (fullname == NULL) {
5390
0
        ret = -1;
5391
0
        goto fail;
5392
0
          }
5393
102k
                            ret = xmlRegExecPushString(exec, fullname, NULL);
5394
102k
          if ((fullname != fn) && (fullname != cur->name))
5395
2
        xmlFree(fullname);
5396
407k
      } else {
5397
407k
          ret = xmlRegExecPushString(exec, cur->name, NULL);
5398
407k
      }
5399
509k
      break;
5400
509k
        default:
5401
15.2k
      break;
5402
952k
    }
5403
    /*
5404
     * Switch to next element
5405
     */
5406
947k
    cur = cur->next;
5407
948k
    while (cur == NULL) {
5408
212k
        cur = nodeVPop(ctxt);
5409
212k
        if (cur == NULL)
5410
212k
      break;
5411
630
        cur = cur->next;
5412
630
    }
5413
947k
      }
5414
214k
      ret = xmlRegExecPushString(exec, NULL, NULL);
5415
218k
fail:
5416
218k
      xmlRegFreeExecCtxt(exec);
5417
218k
  }
5418
218k
    }
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
218k
    if ((warn) && ((ret != 1) && (ret != -3))) {
5540
13.4k
  if (ctxt != NULL) {
5541
13.4k
      char expr[5000];
5542
13.4k
      char list[5000];
5543
5544
13.4k
      expr[0] = 0;
5545
13.4k
      xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5546
13.4k
      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
13.4k
    xmlSnprintfElements(&list[0], 5000, child, 1);
5553
5554
13.4k
      if (name != NULL) {
5555
13.4k
    xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5556
13.4k
     "Element %s content does not follow the DTD, expecting %s, got %s\n",
5557
13.4k
           name, BAD_CAST expr, BAD_CAST list);
5558
13.4k
      } 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
13.4k
  } 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
13.4k
  ret = 0;
5575
13.4k
    }
5576
218k
    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
218k
    ctxt->nodeMax = 0;
5596
218k
    ctxt->nodeNr = 0;
5597
218k
    if (ctxt->nodeTab != NULL) {
5598
750
  xmlFree(ctxt->nodeTab);
5599
750
  ctxt->nodeTab = NULL;
5600
750
    }
5601
218k
    return(ret);
5602
5603
219k
}
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
122k
                           xmlNodePtr elem) {
5618
122k
    int ret = 1;
5619
122k
    xmlNodePtr cur, child;
5620
5621
122k
    if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5622
122k
        (elem->type != XML_ELEMENT_NODE))
5623
0
  return(0);
5624
5625
122k
    child = elem->children;
5626
5627
122k
    cur = child;
5628
241k
    while (cur != NULL) {
5629
119k
  switch (cur->type) {
5630
6.13k
      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
6.13k
    if ((cur->children != NULL) &&
5636
6.13k
        (cur->children->children != NULL)) {
5637
5.72k
        nodeVPush(ctxt, cur);
5638
5.72k
        cur = cur->children->children;
5639
5.72k
        continue;
5640
5.72k
    }
5641
409
    break;
5642
1.31k
      case XML_COMMENT_NODE:
5643
1.43k
      case XML_PI_NODE:
5644
112k
      case XML_TEXT_NODE:
5645
113k
      case XML_CDATA_SECTION_NODE:
5646
113k
    break;
5647
252
      default:
5648
252
    ret = 0;
5649
252
    goto done;
5650
119k
  }
5651
  /*
5652
   * Switch to next element
5653
   */
5654
113k
  cur = cur->next;
5655
119k
  while (cur == NULL) {
5656
113k
      cur = nodeVPop(ctxt);
5657
113k
      if (cur == NULL)
5658
107k
    break;
5659
5.67k
      cur = cur->next;
5660
5.67k
  }
5661
113k
    }
5662
122k
done:
5663
122k
    ctxt->nodeMax = 0;
5664
122k
    ctxt->nodeNr = 0;
5665
122k
    if (ctxt->nodeTab != NULL) {
5666
5.69k
  xmlFree(ctxt->nodeTab);
5667
5.69k
  ctxt->nodeTab = NULL;
5668
5.69k
    }
5669
122k
    return(ret);
5670
122k
}
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
63.5k
                xmlElementContentPtr cont, const xmlChar *qname) {
5686
63.5k
    const xmlChar *name;
5687
63.5k
    int plen;
5688
63.5k
    name = xmlSplitQName3(qname, &plen);
5689
5690
63.5k
    if (name == NULL) {
5691
640k
  while (cont != NULL) {
5692
639k
      if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5693
1.43k
    if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5694
202
        return(1);
5695
638k
      } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5696
638k
         (cont->c1 != NULL) &&
5697
638k
         (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5698
576k
    if ((cont->c1->prefix == NULL) &&
5699
576k
        (xmlStrEqual(cont->c1->name, qname)))
5700
60.5k
        return(1);
5701
576k
      } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5702
62.0k
    (cont->c1 == NULL) ||
5703
62.0k
    (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
578k
      cont = cont->c2;
5710
578k
  }
5711
62.0k
    } else {
5712
5.13k
  while (cont != NULL) {
5713
4.46k
      if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5714
1.20k
    if ((cont->prefix != NULL) &&
5715
1.20k
        (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5716
1.20k
        (xmlStrEqual(cont->name, name)))
5717
529
        return(1);
5718
3.25k
      } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5719
3.25k
         (cont->c1 != NULL) &&
5720
3.25k
         (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5721
1.71k
    if ((cont->c1->prefix != NULL) &&
5722
1.71k
        (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5723
1.71k
        (xmlStrEqual(cont->c1->name, name)))
5724
336
        return(1);
5725
1.71k
      } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5726
1.54k
    (cont->c1 == NULL) ||
5727
1.54k
    (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
3.59k
      cont = cont->c2;
5734
3.59k
  }
5735
1.54k
    }
5736
1.90k
    return(0);
5737
63.5k
}
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.86M
              xmlNodePtr elem, int *extsubset) {
5755
2.86M
    xmlElementPtr elemDecl = NULL;
5756
2.86M
    const xmlChar *prefix = NULL;
5757
5758
2.86M
    if ((ctxt == NULL) || (doc == NULL) ||
5759
2.86M
        (elem == NULL) || (elem->name == NULL))
5760
0
        return(NULL);
5761
2.86M
    if (extsubset != NULL)
5762
2.86M
  *extsubset = 0;
5763
5764
    /*
5765
     * Fetch the declaration for the qualified name
5766
     */
5767
2.86M
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5768
230k
  prefix = elem->ns->prefix;
5769
5770
2.86M
    if (prefix != NULL) {
5771
230k
  elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5772
230k
                             elem->name, prefix);
5773
230k
  if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5774
1.87k
      elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5775
1.87k
                                 elem->name, prefix);
5776
1.87k
      if ((elemDecl != NULL) && (extsubset != NULL))
5777
804
    *extsubset = 1;
5778
1.87k
  }
5779
230k
    }
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.86M
    if (elemDecl == NULL) {
5787
2.63M
  elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5788
2.63M
  if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5789
1.34M
      elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5790
1.34M
      if ((elemDecl != NULL) && (extsubset != NULL))
5791
782k
    *extsubset = 1;
5792
1.34M
  }
5793
2.63M
    }
5794
2.86M
    if (elemDecl == NULL) {
5795
1.77M
  xmlErrValidNode(ctxt, elem,
5796
1.77M
      XML_DTD_UNKNOWN_ELEM,
5797
1.77M
         "No declaration for element %s\n",
5798
1.77M
         elem->name, NULL, NULL);
5799
1.77M
    }
5800
2.86M
    return(elemDecl);
5801
2.86M
}
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
535k
                       xmlNodePtr elem, const xmlChar *qname) {
5818
535k
    int ret = 1;
5819
535k
    xmlElementPtr eDecl;
5820
535k
    int extsubset = 0;
5821
5822
535k
    if (ctxt == NULL)
5823
0
        return(0);
5824
/* printf("PushElem %s\n", qname); */
5825
535k
    if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5826
522k
  xmlValidStatePtr state = ctxt->vstate;
5827
522k
  xmlElementPtr elemDecl;
5828
5829
  /*
5830
   * Check the new element against the content model of the new elem.
5831
   */
5832
522k
  if (state->elemDecl != NULL) {
5833
246k
      elemDecl = state->elemDecl;
5834
5835
246k
      switch(elemDecl->etype) {
5836
2.67k
    case XML_ELEMENT_TYPE_UNDEFINED:
5837
2.67k
        ret = 0;
5838
2.67k
        break;
5839
415
    case XML_ELEMENT_TYPE_EMPTY:
5840
415
        xmlErrValidNode(ctxt, state->node,
5841
415
            XML_DTD_NOT_EMPTY,
5842
415
         "Element %s was declared EMPTY this one has content\n",
5843
415
         state->node->name, NULL, NULL);
5844
415
        ret = 0;
5845
415
        break;
5846
119
    case XML_ELEMENT_TYPE_ANY:
5847
        /* I don't think anything is required then */
5848
119
        break;
5849
64.1k
    case XML_ELEMENT_TYPE_MIXED:
5850
        /* simple case of declared as #PCDATA */
5851
64.1k
        if ((elemDecl->content != NULL) &&
5852
64.1k
      (elemDecl->content->type ==
5853
64.1k
       XML_ELEMENT_CONTENT_PCDATA)) {
5854
611
      xmlErrValidNode(ctxt, state->node,
5855
611
          XML_DTD_NOT_PCDATA,
5856
611
         "Element %s was declared #PCDATA but contains non text nodes\n",
5857
611
        state->node->name, NULL, NULL);
5858
611
      ret = 0;
5859
63.5k
        } else {
5860
63.5k
      ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5861
63.5k
                            qname);
5862
63.5k
      if (ret != 1) {
5863
1.90k
          xmlErrValidNode(ctxt, state->node,
5864
1.90k
              XML_DTD_INVALID_CHILD,
5865
1.90k
         "Element %s is not declared in %s list of possible children\n",
5866
1.90k
            qname, state->node->name, NULL);
5867
1.90k
      }
5868
63.5k
        }
5869
64.1k
        break;
5870
178k
    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
178k
        if (state->exec != NULL) {
5878
178k
      ret = xmlRegExecPushString(state->exec, qname, NULL);
5879
178k
      if (ret < 0) {
5880
6.89k
          xmlErrValidNode(ctxt, state->node,
5881
6.89k
              XML_DTD_CONTENT_MODEL,
5882
6.89k
         "Element %s content does not follow the DTD, Misplaced %s\n",
5883
6.89k
           state->node->name, qname, NULL);
5884
6.89k
          ret = 0;
5885
171k
      } else {
5886
171k
          ret = 1;
5887
171k
      }
5888
178k
        }
5889
178k
        break;
5890
246k
      }
5891
246k
  }
5892
522k
    }
5893
535k
    eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5894
535k
    vstateVPush(ctxt, eDecl, elem);
5895
535k
    return(ret);
5896
535k
}
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
837k
xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5910
837k
    int ret = 1;
5911
5912
/* printf("CDATA %s %d\n", data, len); */
5913
837k
    if (ctxt == NULL)
5914
0
        return(0);
5915
837k
    if (len <= 0)
5916
302
  return(ret);
5917
836k
    if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5918
836k
  xmlValidStatePtr state = ctxt->vstate;
5919
836k
  xmlElementPtr elemDecl;
5920
5921
  /*
5922
   * Check the new element against the content model of the new elem.
5923
   */
5924
836k
  if (state->elemDecl != NULL) {
5925
340k
      elemDecl = state->elemDecl;
5926
5927
340k
      switch(elemDecl->etype) {
5928
3.09k
    case XML_ELEMENT_TYPE_UNDEFINED:
5929
3.09k
        ret = 0;
5930
3.09k
        break;
5931
413
    case XML_ELEMENT_TYPE_EMPTY:
5932
413
        xmlErrValidNode(ctxt, state->node,
5933
413
            XML_DTD_NOT_EMPTY,
5934
413
         "Element %s was declared EMPTY this one has content\n",
5935
413
         state->node->name, NULL, NULL);
5936
413
        ret = 0;
5937
413
        break;
5938
142
    case XML_ELEMENT_TYPE_ANY:
5939
142
        break;
5940
163k
    case XML_ELEMENT_TYPE_MIXED:
5941
163k
        break;
5942
173k
    case XML_ELEMENT_TYPE_ELEMENT: {
5943
173k
                    int i;
5944
5945
788k
                    for (i = 0;i < len;i++) {
5946
616k
                        if (!IS_BLANK_CH(data[i])) {
5947
2.48k
                            xmlErrValidNode(ctxt, state->node,
5948
2.48k
                                            XML_DTD_CONTENT_MODEL,
5949
2.48k
       "Element %s content does not follow the DTD, Text not allowed\n",
5950
2.48k
                                   state->node->name, NULL, NULL);
5951
2.48k
                            ret = 0;
5952
2.48k
                            goto done;
5953
2.48k
                        }
5954
616k
                    }
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
171k
                    break;
5962
173k
                }
5963
340k
      }
5964
340k
  }
5965
836k
    }
5966
836k
done:
5967
836k
    return(ret);
5968
836k
}
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
535k
          const xmlChar *qname ATTRIBUTE_UNUSED) {
5985
535k
    int ret = 1;
5986
5987
535k
    if (ctxt == NULL)
5988
0
        return(0);
5989
/* printf("PopElem %s\n", qname); */
5990
535k
    if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5991
535k
  xmlValidStatePtr state = ctxt->vstate;
5992
535k
  xmlElementPtr elemDecl;
5993
5994
  /*
5995
   * Check the new element against the content model of the new elem.
5996
   */
5997
535k
  if (state->elemDecl != NULL) {
5998
220k
      elemDecl = state->elemDecl;
5999
6000
220k
      if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
6001
76.8k
    if (state->exec != NULL) {
6002
76.8k
        ret = xmlRegExecPushString(state->exec, NULL, NULL);
6003
76.8k
        if (ret == 0) {
6004
1.62k
      xmlErrValidNode(ctxt, state->node,
6005
1.62k
                      XML_DTD_CONTENT_MODEL,
6006
1.62k
     "Element %s content does not follow the DTD, Expecting more child\n",
6007
1.62k
             state->node->name, NULL,NULL);
6008
75.2k
        } else {
6009
      /*
6010
       * previous validation errors should not generate
6011
       * a new one here
6012
       */
6013
75.2k
      ret = 1;
6014
75.2k
        }
6015
76.8k
    }
6016
76.8k
      }
6017
220k
  }
6018
535k
  vstateVPop(ctxt);
6019
535k
    }
6020
535k
    return(ret);
6021
535k
}
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.32M
                      xmlNodePtr elem) {
6045
2.32M
    xmlElementPtr elemDecl = NULL;
6046
2.32M
    xmlElementContentPtr cont;
6047
2.32M
    xmlAttributePtr attr;
6048
2.32M
    xmlNodePtr child;
6049
2.32M
    int ret = 1, tmp;
6050
2.32M
    const xmlChar *name;
6051
2.32M
    int extsubset = 0;
6052
6053
2.32M
    CHECK_DTD;
6054
6055
2.32M
    if (elem == NULL) return(0);
6056
2.32M
    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
5.27k
        case XML_TEXT_NODE:
6062
5.27k
      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
5.27k
      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
5.27k
      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
5.27k
      return(1);
6081
0
        case XML_XINCLUDE_START:
6082
0
        case XML_XINCLUDE_END:
6083
0
            return(1);
6084
81
        case XML_CDATA_SECTION_NODE:
6085
81
        case XML_ENTITY_REF_NODE:
6086
219
        case XML_PI_NODE:
6087
384
        case XML_COMMENT_NODE:
6088
384
      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.32M
        case XML_ELEMENT_NODE:
6108
2.32M
      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.32M
    }
6114
6115
    /*
6116
     * Fetch the declaration
6117
     */
6118
2.32M
    elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6119
2.32M
    if (elemDecl == NULL)
6120
1.45M
  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
869k
    if (ctxt->vstateNr == 0) {
6127
    /* Check that the element content matches the definition */
6128
697k
    switch (elemDecl->etype) {
6129
15.2k
        case XML_ELEMENT_TYPE_UNDEFINED:
6130
15.2k
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6131
15.2k
                      "No declaration for element %s\n",
6132
15.2k
       elem->name, NULL, NULL);
6133
15.2k
      return(0);
6134
96.4k
        case XML_ELEMENT_TYPE_EMPTY:
6135
96.4k
      if (elem->children != NULL) {
6136
174
    xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
6137
174
         "Element %s was declared EMPTY this one has content\n",
6138
174
                 elem->name, NULL, NULL);
6139
174
    ret = 0;
6140
174
      }
6141
96.4k
      break;
6142
144
        case XML_ELEMENT_TYPE_ANY:
6143
      /* I don't think anything is required then */
6144
144
      break;
6145
366k
        case XML_ELEMENT_TYPE_MIXED:
6146
6147
      /* simple case of declared as #PCDATA */
6148
366k
      if ((elemDecl->content != NULL) &&
6149
366k
    (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6150
122k
    ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6151
122k
    if (!ret) {
6152
252
        xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
6153
252
         "Element %s was declared #PCDATA but contains non text nodes\n",
6154
252
         elem->name, NULL, NULL);
6155
252
    }
6156
122k
    break;
6157
122k
      }
6158
244k
      child = elem->children;
6159
      /* Hum, this start to get messy */
6160
850k
      while (child != NULL) {
6161
606k
          if (child->type == XML_ELEMENT_NODE) {
6162
191k
        name = child->name;
6163
191k
        if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
6164
956
      xmlChar fn[50];
6165
956
      xmlChar *fullname;
6166
6167
956
      fullname = xmlBuildQName(child->name, child->ns->prefix,
6168
956
                         fn, 50);
6169
956
      if (fullname == NULL)
6170
0
          return(0);
6171
956
      cont = elemDecl->content;
6172
4.37k
      while (cont != NULL) {
6173
3.42k
          if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6174
956
        if (xmlStrEqual(cont->name, fullname))
6175
9
            break;
6176
2.47k
          } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6177
2.47k
             (cont->c1 != NULL) &&
6178
2.47k
             (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
6179
1.51k
        if (xmlStrEqual(cont->c1->name, fullname))
6180
0
            break;
6181
1.51k
          } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6182
956
        (cont->c1 == NULL) ||
6183
956
        (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
3.41k
          cont = cont->c2;
6190
3.41k
      }
6191
956
      if ((fullname != fn) && (fullname != child->name))
6192
0
          xmlFree(fullname);
6193
956
      if (cont != NULL)
6194
9
          goto child_ok;
6195
956
        }
6196
191k
        cont = elemDecl->content;
6197
1.93M
        while (cont != NULL) {
6198
1.93M
            if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6199
2.19k
          if (xmlStrEqual(cont->name, name)) break;
6200
1.93M
      } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6201
1.93M
         (cont->c1 != NULL) &&
6202
1.93M
         (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6203
1.73M
          if (xmlStrEqual(cont->c1->name, name)) break;
6204
1.73M
      } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6205
191k
          (cont->c1 == NULL) ||
6206
191k
          (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
1.74M
      cont = cont->c2;
6213
1.74M
        }
6214
191k
        if (cont == NULL) {
6215
1.61k
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
6216
1.61k
         "Element %s is not declared in %s list of possible children\n",
6217
1.61k
             name, elem->name, NULL);
6218
1.61k
      ret = 0;
6219
1.61k
        }
6220
191k
    }
6221
606k
child_ok:
6222
606k
          child = child->next;
6223
606k
      }
6224
244k
      break;
6225
244k
        case XML_ELEMENT_TYPE_ELEMENT:
6226
219k
      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
219k
      child = elem->children;
6252
219k
      cont = elemDecl->content;
6253
219k
      tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
6254
219k
      if (tmp <= 0)
6255
13.9k
    ret = tmp;
6256
219k
      break;
6257
697k
    }
6258
697k
    } /* not continuous */
6259
6260
    /* [ VC: Required Attribute ] */
6261
854k
    attr = elemDecl->attributes;
6262
2.49M
    while (attr != NULL) {
6263
1.63M
  if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6264
279k
      int qualified = -1;
6265
6266
279k
      if ((attr->prefix == NULL) &&
6267
279k
    (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6268
6
    xmlNsPtr ns;
6269
6270
6
    ns = elem->nsDef;
6271
9
    while (ns != NULL) {
6272
3
        if (ns->prefix == NULL)
6273
0
      goto found;
6274
3
        ns = ns->next;
6275
3
    }
6276
279k
      } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6277
489
    xmlNsPtr ns;
6278
6279
489
    ns = elem->nsDef;
6280
930
    while (ns != NULL) {
6281
729
        if (xmlStrEqual(attr->name, ns->prefix))
6282
288
      goto found;
6283
441
        ns = ns->next;
6284
441
    }
6285
279k
      } else {
6286
279k
    xmlAttrPtr attrib;
6287
6288
279k
    attrib = elem->properties;
6289
339k
    while (attrib != NULL) {
6290
327k
        if (xmlStrEqual(attrib->name, attr->name)) {
6291
269k
      if (attr->prefix != NULL) {
6292
158k
          xmlNsPtr nameSpace = attrib->ns;
6293
6294
158k
          if (nameSpace == NULL)
6295
306
        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
158k
          if (nameSpace == NULL) {
6302
15
        if (qualified < 0)
6303
15
            qualified = 0;
6304
158k
          } else if (!xmlStrEqual(nameSpace->prefix,
6305
158k
                attr->prefix)) {
6306
2.26k
        if (qualified < 1)
6307
2.26k
            qualified = 1;
6308
2.26k
          } else
6309
156k
        goto found;
6310
158k
      } 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
110k
          goto found;
6318
110k
      }
6319
269k
        }
6320
60.5k
        attrib = attrib->next;
6321
60.5k
    }
6322
279k
      }
6323
12.2k
      if (qualified == -1) {
6324
9.99k
    if (attr->prefix == NULL) {
6325
2.26k
        xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6326
2.26k
           "Element %s does not carry attribute %s\n",
6327
2.26k
         elem->name, attr->name, NULL);
6328
2.26k
        ret = 0;
6329
7.72k
          } else {
6330
7.72k
        xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6331
7.72k
           "Element %s does not carry attribute %s:%s\n",
6332
7.72k
         elem->name, attr->prefix,attr->name);
6333
7.72k
        ret = 0;
6334
7.72k
    }
6335
9.99k
      } else if (qualified == 0) {
6336
15
    xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6337
15
       "Element %s required attribute %s:%s has no prefix\n",
6338
15
           elem->name, attr->prefix, attr->name);
6339
2.26k
      } else if (qualified == 1) {
6340
2.26k
    xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6341
2.26k
       "Element %s required attribute %s:%s has different prefix\n",
6342
2.26k
           elem->name, attr->prefix, attr->name);
6343
2.26k
      }
6344
1.35M
  } 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
81.2k
      if ((attr->prefix == NULL) &&
6351
81.2k
    (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6352
654
    xmlNsPtr ns;
6353
6354
654
    ns = elem->nsDef;
6355
750
    while (ns != NULL) {
6356
750
        if (ns->prefix == NULL) {
6357
654
      if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6358
306
          xmlErrValidNode(ctxt, elem,
6359
306
                 XML_DTD_ELEM_DEFAULT_NAMESPACE,
6360
306
   "Element %s namespace name for default namespace does not match the DTD\n",
6361
306
           elem->name, NULL, NULL);
6362
306
          ret = 0;
6363
306
      }
6364
654
      goto found;
6365
654
        }
6366
96
        ns = ns->next;
6367
96
    }
6368
80.6k
      } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6369
1.46k
    xmlNsPtr ns;
6370
6371
1.46k
    ns = elem->nsDef;
6372
1.62k
    while (ns != NULL) {
6373
1.34k
        if (xmlStrEqual(attr->name, ns->prefix)) {
6374
1.19k
      if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6375
81
          xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6376
81
       "Element %s namespace name for %s does not match the DTD\n",
6377
81
           elem->name, ns->prefix, NULL);
6378
81
          ret = 0;
6379
81
      }
6380
1.19k
      goto found;
6381
1.19k
        }
6382
156
        ns = ns->next;
6383
156
    }
6384
1.46k
      }
6385
81.2k
  }
6386
1.63M
found:
6387
1.63M
        attr = attr->nexth;
6388
1.63M
    }
6389
854k
    return(ret);
6390
854k
}
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
247k
xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6408
247k
    xmlNodePtr root;
6409
247k
    int ret;
6410
6411
247k
    if (doc == NULL) return(0);
6412
6413
247k
    root = xmlDocGetRootElement(doc);
6414
247k
    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
247k
    if ((doc->intSubset != NULL) &&
6425
247k
  (doc->intSubset->name != NULL)) {
6426
  /*
6427
   * Check first the document root against the NQName
6428
   */
6429
246k
  if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6430
55.8k
      if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6431
11.2k
    xmlChar fn[50];
6432
11.2k
    xmlChar *fullname;
6433
6434
11.2k
    fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6435
11.2k
    if (fullname == NULL) {
6436
0
        xmlVErrMemory(ctxt, NULL);
6437
0
        return(0);
6438
0
    }
6439
11.2k
    ret = xmlStrEqual(doc->intSubset->name, fullname);
6440
11.2k
    if ((fullname != fn) && (fullname != root->name))
6441
20
        xmlFree(fullname);
6442
11.2k
    if (ret == 1)
6443
10.0k
        goto name_ok;
6444
11.2k
      }
6445
45.8k
      if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6446
45.8k
    (xmlStrEqual(root->name, BAD_CAST "html")))
6447
0
    goto name_ok;
6448
45.8k
      xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6449
45.8k
       "root and DTD name do not match '%s' and '%s'\n",
6450
45.8k
       root->name, doc->intSubset->name, NULL);
6451
45.8k
      return(0);
6452
45.8k
  }
6453
246k
    }
6454
201k
name_ok:
6455
201k
    return(1);
6456
247k
}
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
3
  return(1);
6496
3
    }
6497
6498
15.4k
    ret &= xmlValidateOneElement(ctxt, doc, elem);
6499
15.4k
    if (elem->type == XML_ELEMENT_NODE) {
6500
9.75k
  attr = elem->properties;
6501
10.8k
  while (attr != NULL) {
6502
1.13k
      value = xmlNodeListGetString(doc, attr->children, 0);
6503
1.13k
      ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6504
1.13k
      if (value != NULL)
6505
1.13k
    xmlFree((char *)value);
6506
1.13k
      attr= attr->next;
6507
1.13k
  }
6508
9.75k
  ns = elem->nsDef;
6509
10.4k
  while (ns != NULL) {
6510
718
      if (elem->ns == NULL)
6511
358
    ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6512
358
                 ns, ns->href);
6513
360
      else
6514
360
    ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6515
360
                                   elem->ns->prefix, ns, ns->href);
6516
718
      ns = ns->next;
6517
718
  }
6518
9.75k
    }
6519
15.4k
    child = elem->children;
6520
21.5k
    while (child != NULL) {
6521
6.10k
        ret &= xmlValidateElement(ctxt, doc, child);
6522
6.10k
        child = child->next;
6523
6.10k
    }
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
7.80k
                     const xmlChar *name) {
6538
7.80k
    xmlAttrPtr id;
6539
7.80k
    xmlAttrPtr attr;
6540
6541
7.80k
    if (ref == NULL)
6542
0
  return;
6543
7.80k
    if ((ref->attr == NULL) && (ref->name == NULL))
6544
0
  return;
6545
7.80k
    attr = ref->attr;
6546
7.80k
    if (attr == NULL) {
6547
2.70k
  xmlChar *dup, *str = NULL, *cur, save;
6548
6549
2.70k
  dup = xmlStrdup(name);
6550
2.70k
  if (dup == NULL) {
6551
0
      ctxt->valid = 0;
6552
0
      return;
6553
0
  }
6554
2.70k
  cur = dup;
6555
3.41k
  while (*cur != 0) {
6556
3.41k
      str = cur;
6557
26.6k
      while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6558
3.41k
      save = *cur;
6559
3.41k
      *cur = 0;
6560
3.41k
      id = xmlGetID(ctxt->doc, str);
6561
3.41k
      if (id == NULL) {
6562
1.77k
    xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6563
1.77k
     "attribute %s line %d references an unknown ID \"%s\"\n",
6564
1.77k
           ref->name, ref->lineno, str);
6565
1.77k
    ctxt->valid = 0;
6566
1.77k
      }
6567
3.41k
      if (save == 0)
6568
2.70k
    break;
6569
710
      *cur = save;
6570
710
      while (IS_BLANK_CH(*cur)) cur++;
6571
710
  }
6572
2.70k
  xmlFree(dup);
6573
5.10k
    } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6574
4.26k
  id = xmlGetID(ctxt->doc, name);
6575
4.26k
  if (id == NULL) {
6576
1.50k
      xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6577
1.50k
     "IDREF attribute %s references an unknown ID \"%s\"\n",
6578
1.50k
       attr->name, name, NULL);
6579
1.50k
      ctxt->valid = 0;
6580
1.50k
  }
6581
4.26k
    } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6582
842
  xmlChar *dup, *str = NULL, *cur, save;
6583
6584
842
  dup = xmlStrdup(name);
6585
842
  if (dup == NULL) {
6586
0
      xmlVErrMemory(ctxt, "IDREFS split");
6587
0
      ctxt->valid = 0;
6588
0
      return;
6589
0
  }
6590
842
  cur = dup;
6591
1.96k
  while (*cur != 0) {
6592
1.96k
      str = cur;
6593
14.4k
      while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6594
1.96k
      save = *cur;
6595
1.96k
      *cur = 0;
6596
1.96k
      id = xmlGetID(ctxt->doc, str);
6597
1.96k
      if (id == NULL) {
6598
1.96k
    xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6599
1.96k
     "IDREFS attribute %s references an unknown ID \"%s\"\n",
6600
1.96k
           attr->name, str, NULL);
6601
1.96k
    ctxt->valid = 0;
6602
1.96k
      }
6603
1.96k
      if (save == 0)
6604
842
    break;
6605
1.12k
      *cur = save;
6606
1.12k
      while (IS_BLANK_CH(*cur)) cur++;
6607
1.12k
  }
6608
842
  xmlFree(dup);
6609
842
    }
6610
7.80k
}
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
7.80k
{
6622
7.80k
  xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6623
7.80k
  xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6624
7.80k
  return 1;
6625
7.80k
}
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
5.24k
xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) {
6636
5.24k
    xmlListPtr ref_list = (xmlListPtr) payload;
6637
5.24k
    xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6638
5.24k
    xmlValidateMemo memo;
6639
6640
5.24k
    if (ref_list == NULL)
6641
0
  return;
6642
5.24k
    memo.ctxt = ctxt;
6643
5.24k
    memo.name = name;
6644
6645
5.24k
    xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6646
6647
5.24k
}
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
15.3k
xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6666
15.3k
    xmlRefTablePtr table;
6667
15.3k
    unsigned int save;
6668
6669
15.3k
    if (ctxt == NULL)
6670
0
        return(0);
6671
15.3k
    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
15.3k
    save = ctxt->flags;
6679
15.3k
    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
15.3k
    table = (xmlRefTablePtr) doc->refs;
6691
15.3k
    ctxt->doc = doc;
6692
15.3k
    ctxt->valid = 1;
6693
15.3k
    xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
6694
6695
15.3k
    ctxt->flags = save;
6696
15.3k
    return(ctxt->valid);
6697
15.3k
}
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
485k
                      const xmlChar *name ATTRIBUTE_UNUSED) {
6752
485k
    xmlEntityPtr cur = (xmlEntityPtr) payload;
6753
485k
    xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6754
485k
    if (cur == NULL)
6755
0
  return;
6756
485k
    if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6757
12.4k
  xmlChar *notation = cur->content;
6758
6759
12.4k
  if (notation != NULL) {
6760
12.3k
      int ret;
6761
6762
12.3k
      ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6763
12.3k
      if (ret != 1) {
6764
12.3k
    ctxt->valid = 0;
6765
12.3k
      }
6766
12.3k
  }
6767
12.4k
    }
6768
485k
}
6769
6770
static void
6771
xmlValidateAttributeCallback(void *payload, void *data,
6772
2.20M
                       const xmlChar *name ATTRIBUTE_UNUSED) {
6773
2.20M
    xmlAttributePtr cur = (xmlAttributePtr) payload;
6774
2.20M
    xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6775
2.20M
    int ret;
6776
2.20M
    xmlDocPtr doc;
6777
2.20M
    xmlElementPtr elem = NULL;
6778
6779
2.20M
    if (cur == NULL)
6780
0
  return;
6781
2.20M
    switch (cur->atype) {
6782
673k
  case XML_ATTRIBUTE_CDATA:
6783
1.33M
  case XML_ATTRIBUTE_ID:
6784
1.38M
  case XML_ATTRIBUTE_IDREF  :
6785
1.39M
  case XML_ATTRIBUTE_IDREFS:
6786
2.00M
  case XML_ATTRIBUTE_NMTOKEN:
6787
2.05M
  case XML_ATTRIBUTE_NMTOKENS:
6788
2.20M
  case XML_ATTRIBUTE_ENUMERATION:
6789
2.20M
      break;
6790
2.60k
  case XML_ATTRIBUTE_ENTITY:
6791
2.95k
  case XML_ATTRIBUTE_ENTITIES:
6792
3.31k
  case XML_ATTRIBUTE_NOTATION:
6793
3.31k
      if (cur->defaultValue != NULL) {
6794
6795
195
    ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6796
195
                               cur->atype, cur->defaultValue);
6797
195
    if ((ret == 0) && (ctxt->valid == 1))
6798
195
        ctxt->valid = 0;
6799
195
      }
6800
3.31k
      if (cur->tree != NULL) {
6801
360
    xmlEnumerationPtr tree = cur->tree;
6802
745
    while (tree != NULL) {
6803
385
        ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6804
385
            cur->name, cur->atype, tree->name);
6805
385
        if ((ret == 0) && (ctxt->valid == 1))
6806
320
      ctxt->valid = 0;
6807
385
        tree = tree->next;
6808
385
    }
6809
360
      }
6810
2.20M
    }
6811
2.20M
    if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6812
360
  doc = cur->doc;
6813
360
  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
360
  if (doc != NULL)
6821
360
      elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6822
360
  if ((elem == NULL) && (doc != NULL))
6823
162
      elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6824
360
  if ((elem == NULL) && (cur->parent != NULL) &&
6825
360
      (cur->parent->type == XML_DTD_NODE))
6826
0
      elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
6827
360
  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
360
  if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6834
50
      xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6835
50
       "NOTATION attribute %s declared for EMPTY element %s\n",
6836
50
       cur->name, cur->elem, NULL);
6837
50
      ctxt->valid = 0;
6838
50
  }
6839
360
    }
6840
2.20M
}
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
247k
xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6861
247k
    xmlDtdPtr dtd;
6862
247k
    xmlAttributeTablePtr table;
6863
247k
    xmlEntitiesTablePtr entities;
6864
6865
247k
    if ((doc == NULL) || (ctxt == NULL)) return(0);
6866
247k
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6867
0
  return(0);
6868
247k
    ctxt->doc = doc;
6869
247k
    ctxt->valid = 1;
6870
247k
    dtd = doc->intSubset;
6871
247k
    if ((dtd != NULL) && (dtd->attributes != NULL)) {
6872
52.2k
  table = (xmlAttributeTablePtr) dtd->attributes;
6873
52.2k
  xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6874
52.2k
    }
6875
247k
    if ((dtd != NULL) && (dtd->entities != NULL)) {
6876
191k
  entities = (xmlEntitiesTablePtr) dtd->entities;
6877
191k
  xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6878
191k
    }
6879
247k
    dtd = doc->extSubset;
6880
247k
    if ((dtd != NULL) && (dtd->attributes != NULL)) {
6881
10.6k
  table = (xmlAttributeTablePtr) dtd->attributes;
6882
10.6k
  xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6883
10.6k
    }
6884
247k
    if ((dtd != NULL) && (dtd->entities != NULL)) {
6885
11.8k
  entities = (xmlEntitiesTablePtr) dtd->entities;
6886
11.8k
  xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6887
11.8k
    }
6888
247k
    return(ctxt->valid);
6889
247k
}
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