Coverage Report

Created: 2024-02-04 06:19

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