Coverage Report

Created: 2025-07-07 10:01

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