Coverage Report

Created: 2025-07-18 06:31

/src/libxml2/valid.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * valid.c : part of the code use to do the DTD handling and the validity
3
 *           checking
4
 *
5
 * See Copyright for the status of this software.
6
 *
7
 * daniel@veillard.com
8
 */
9
10
#define IN_LIBXML
11
#include "libxml.h"
12
13
#include <string.h>
14
#include <stdlib.h>
15
16
#include <libxml/xmlmemory.h>
17
#include <libxml/hash.h>
18
#include <libxml/uri.h>
19
#include <libxml/valid.h>
20
#include <libxml/parser.h>
21
#include <libxml/parserInternals.h>
22
#include <libxml/xmlerror.h>
23
#include <libxml/list.h>
24
#include <libxml/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
{
141
    xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str2, str3, 0,
142
                  msg, str1, str2, str3);
143
}
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
{
162
    xmlDoErrValid(ctxt, node, error, XML_ERR_ERROR, str1, str3, NULL, int2,
163
                  msg, str1, int2, str3);
164
}
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
{
183
    xmlDoErrValid(ctxt, node, error, XML_ERR_WARNING, str1, str2, str3, 0,
184
                  msg, str1, str2, str3);
185
}
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
vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
208
    if (ctxt->vstateNr >= ctxt->vstateMax) {
209
        xmlValidState *tmp;
210
        int newSize;
211
212
        newSize = xmlGrowCapacity(ctxt->vstateMax, sizeof(tmp[0]),
213
                                  10, XML_MAX_ITEMS);
214
        if (newSize < 0) {
215
      xmlVErrMemory(ctxt);
216
      return(-1);
217
  }
218
  tmp = xmlRealloc(ctxt->vstateTab, newSize * sizeof(tmp[0]));
219
        if (tmp == NULL) {
220
      xmlVErrMemory(ctxt);
221
      return(-1);
222
  }
223
  ctxt->vstateTab = tmp;
224
  ctxt->vstateMax = newSize;
225
    }
226
    ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
227
    ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
228
    ctxt->vstateTab[ctxt->vstateNr].node = node;
229
    if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
230
  if (elemDecl->contModel == NULL)
231
      xmlValidBuildContentModel(ctxt, elemDecl);
232
  if (elemDecl->contModel != NULL) {
233
      ctxt->vstateTab[ctxt->vstateNr].exec =
234
    xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
235
            if (ctxt->vstateTab[ctxt->vstateNr].exec == NULL) {
236
                xmlVErrMemory(ctxt);
237
                return(-1);
238
            }
239
  } else {
240
      ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
241
      xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
242
                      XML_ERR_INTERNAL_ERROR,
243
          "Failed to build content model regexp for %s\n",
244
          node->name, NULL, NULL);
245
  }
246
    }
247
    return(ctxt->vstateNr++);
248
}
249
250
static int
251
vstateVPop(xmlValidCtxtPtr ctxt) {
252
    xmlElementPtr elemDecl;
253
254
    if (ctxt->vstateNr < 1) return(-1);
255
    ctxt->vstateNr--;
256
    elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
257
    ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
258
    ctxt->vstateTab[ctxt->vstateNr].node = NULL;
259
    if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
260
  xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
261
    }
262
    ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
263
    if (ctxt->vstateNr >= 1)
264
  ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
265
    else
266
  ctxt->vstate = NULL;
267
    return(ctxt->vstateNr);
268
}
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
{
366
    if (ctxt->nodeNr >= ctxt->nodeMax) {
367
        xmlNodePtr *tmp;
368
        int newSize;
369
370
        newSize = xmlGrowCapacity(ctxt->nodeMax, sizeof(tmp[0]),
371
                                  4, XML_MAX_ITEMS);
372
        if (newSize < 0) {
373
      xmlVErrMemory(ctxt);
374
            return (-1);
375
        }
376
        tmp = xmlRealloc(ctxt->nodeTab, newSize * sizeof(tmp[0]));
377
        if (tmp == NULL) {
378
      xmlVErrMemory(ctxt);
379
            return (-1);
380
        }
381
  ctxt->nodeTab = tmp;
382
        ctxt->nodeMax = newSize;
383
    }
384
    ctxt->nodeTab[ctxt->nodeNr] = value;
385
    ctxt->node = value;
386
    return (ctxt->nodeNr++);
387
}
388
static xmlNodePtr
389
nodeVPop(xmlValidCtxtPtr ctxt)
390
{
391
    xmlNodePtr ret;
392
393
    if (ctxt->nodeNr <= 0)
394
        return (NULL);
395
    ctxt->nodeNr--;
396
    if (ctxt->nodeNr > 0)
397
        ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
398
    else
399
        ctxt->node = NULL;
400
    ret = ctxt->nodeTab[ctxt->nodeNr];
401
    ctxt->nodeTab[ctxt->nodeNr] = NULL;
402
    return (ret);
403
}
404
405
/* TODO: use hash table for accesses to elem and attribute definitions */
406
407
408
#define CHECK_DTD           \
409
   if (doc == NULL) return(0);          \
410
   else if ((doc->intSubset == NULL) &&       \
411
      (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
               const xmlChar *name) {
435
    if (content == NULL) {
436
  xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
437
      "Found NULL content in content model of %s\n",
438
      name, NULL, NULL);
439
  return(0);
440
    }
441
    switch (content->type) {
442
  case XML_ELEMENT_CONTENT_PCDATA:
443
      xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
444
          "Found PCDATA in content model of %s\n",
445
                name, NULL, NULL);
446
      return(0);
447
      break;
448
  case XML_ELEMENT_CONTENT_ELEMENT: {
449
      xmlAutomataStatePtr oldstate = ctxt->state;
450
      xmlChar fn[50];
451
      xmlChar *fullname;
452
453
      fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
454
      if (fullname == NULL) {
455
          xmlVErrMemory(ctxt);
456
    return(0);
457
      }
458
459
      switch (content->ocur) {
460
    case XML_ELEMENT_CONTENT_ONCE:
461
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
462
          ctxt->state, NULL, fullname, NULL);
463
        break;
464
    case XML_ELEMENT_CONTENT_OPT:
465
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
466
          ctxt->state, NULL, fullname, NULL);
467
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
468
        break;
469
    case XML_ELEMENT_CONTENT_PLUS:
470
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
471
          ctxt->state, NULL, fullname, NULL);
472
        xmlAutomataNewTransition(ctxt->am, ctxt->state,
473
                           ctxt->state, fullname, NULL);
474
        break;
475
    case XML_ELEMENT_CONTENT_MULT:
476
        ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
477
              ctxt->state, NULL);
478
        xmlAutomataNewTransition(ctxt->am,
479
          ctxt->state, ctxt->state, fullname, NULL);
480
        break;
481
      }
482
      if ((fullname != fn) && (fullname != content->name))
483
    xmlFree(fullname);
484
      break;
485
  }
486
  case XML_ELEMENT_CONTENT_SEQ: {
487
      xmlAutomataStatePtr oldstate, oldend;
488
      xmlElementContentOccur ocur;
489
490
      /*
491
       * Simply iterate over the content
492
       */
493
      oldstate = ctxt->state;
494
      ocur = content->ocur;
495
      if (ocur != XML_ELEMENT_CONTENT_ONCE) {
496
    ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
497
    oldstate = ctxt->state;
498
      }
499
      do {
500
    if (xmlValidBuildAContentModel(content->c1, ctxt, name) == 0)
501
                    return(0);
502
    content = content->c2;
503
      } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
504
         (content->ocur == XML_ELEMENT_CONTENT_ONCE));
505
      if (xmlValidBuildAContentModel(content, ctxt, name) == 0)
506
                return(0);
507
      oldend = ctxt->state;
508
      ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
509
      switch (ocur) {
510
    case XML_ELEMENT_CONTENT_ONCE:
511
        break;
512
    case XML_ELEMENT_CONTENT_OPT:
513
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
514
        break;
515
    case XML_ELEMENT_CONTENT_MULT:
516
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
517
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
518
        break;
519
    case XML_ELEMENT_CONTENT_PLUS:
520
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
521
        break;
522
      }
523
      break;
524
  }
525
  case XML_ELEMENT_CONTENT_OR: {
526
      xmlAutomataStatePtr oldstate, oldend;
527
      xmlElementContentOccur ocur;
528
529
      ocur = content->ocur;
530
      if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
531
    (ocur == XML_ELEMENT_CONTENT_MULT)) {
532
    ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
533
      ctxt->state, NULL);
534
      }
535
      oldstate = ctxt->state;
536
      oldend = xmlAutomataNewState(ctxt->am);
537
538
      /*
539
       * iterate over the subtypes and remerge the end with an
540
       * epsilon transition
541
       */
542
      do {
543
    ctxt->state = oldstate;
544
    if (xmlValidBuildAContentModel(content->c1, ctxt, name) == 0)
545
                    return(0);
546
    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
547
    content = content->c2;
548
      } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
549
         (content->ocur == XML_ELEMENT_CONTENT_ONCE));
550
      ctxt->state = oldstate;
551
      if (xmlValidBuildAContentModel(content, ctxt, name) == 0)
552
                return(0);
553
      xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
554
      ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
555
      switch (ocur) {
556
    case XML_ELEMENT_CONTENT_ONCE:
557
        break;
558
    case XML_ELEMENT_CONTENT_OPT:
559
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
560
        break;
561
    case XML_ELEMENT_CONTENT_MULT:
562
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
563
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
564
        break;
565
    case XML_ELEMENT_CONTENT_PLUS:
566
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
567
        break;
568
      }
569
      break;
570
  }
571
  default:
572
      xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
573
                  "ContentModel broken for element %s\n",
574
      (const char *) name);
575
      return(0);
576
    }
577
    return(1);
578
}
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
xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
593
    int ret = 0;
594
595
    if ((ctxt == NULL) || (elem == NULL))
596
  return(0);
597
    if (elem->type != XML_ELEMENT_DECL)
598
  return(0);
599
    if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
600
  return(1);
601
    /* TODO: should we rebuild in this case ? */
602
    if (elem->contModel != NULL) {
603
  if (!xmlRegexpIsDeterminist(elem->contModel)) {
604
      ctxt->valid = 0;
605
      return(0);
606
  }
607
  return(1);
608
    }
609
610
    ctxt->am = xmlNewAutomata();
611
    if (ctxt->am == NULL) {
612
        xmlVErrMemory(ctxt);
613
  return(0);
614
    }
615
    ctxt->state = xmlAutomataGetInitState(ctxt->am);
616
    if (xmlValidBuildAContentModel(elem->content, ctxt, elem->name) == 0)
617
        goto done;
618
    xmlAutomataSetFinalState(ctxt->am, ctxt->state);
619
    elem->contModel = xmlAutomataCompile(ctxt->am);
620
    if (elem->contModel == NULL) {
621
        xmlVErrMemory(ctxt);
622
        goto done;
623
    }
624
    if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
625
  char expr[5000];
626
  expr[0] = 0;
627
  xmlSnprintfElementContent(expr, 5000, elem->content, 1);
628
  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
629
                  XML_DTD_CONTENT_NOT_DETERMINIST,
630
         "Content model of %s is not deterministic: %s\n",
631
         elem->name, BAD_CAST expr, NULL);
632
        ctxt->valid = 0;
633
  goto done;
634
    }
635
636
    ret = 1;
637
638
done:
639
    ctxt->state = NULL;
640
    xmlFreeAutomata(ctxt->am);
641
    ctxt->am = NULL;
642
    return(ret);
643
}
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
xmlValidCtxtPtr xmlNewValidCtxt(void) {
661
    xmlValidCtxtPtr ret;
662
663
    ret = xmlMalloc(sizeof (xmlValidCtxt));
664
    if (ret == NULL)
665
  return (NULL);
666
667
    (void) memset(ret, 0, sizeof (xmlValidCtxt));
668
669
    return (ret);
670
}
671
672
/**
673
 * xmlFreeValidCtxt:
674
 * @cur:  the validation context to free
675
 *
676
 * Free a validation context structure.
677
 */
678
void
679
xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
680
    if (cur == NULL)
681
        return;
682
    if (cur->vstateTab != NULL)
683
        xmlFree(cur->vstateTab);
684
    if (cur->nodeTab != NULL)
685
        xmlFree(cur->nodeTab);
686
    xmlFree(cur);
687
}
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
0
                        xmlElementContentType type) {
706
0
    xmlElementContentPtr ret;
707
0
    xmlDictPtr dict = NULL;
708
709
0
    if (doc != NULL)
710
0
        dict = doc->dict;
711
712
0
    switch(type) {
713
0
  case XML_ELEMENT_CONTENT_ELEMENT:
714
0
      if (name == NULL) {
715
0
          xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
716
0
      "xmlNewElementContent : name == NULL !\n",
717
0
      NULL);
718
0
      }
719
0
      break;
720
0
        case XML_ELEMENT_CONTENT_PCDATA:
721
0
  case XML_ELEMENT_CONTENT_SEQ:
722
0
  case XML_ELEMENT_CONTENT_OR:
723
0
      if (name != NULL) {
724
0
          xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
725
0
      "xmlNewElementContent : name != NULL !\n",
726
0
      NULL);
727
0
      }
728
0
      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
0
    }
735
0
    ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
736
0
    if (ret == NULL)
737
0
  return(NULL);
738
0
    memset(ret, 0, sizeof(xmlElementContent));
739
0
    ret->type = type;
740
0
    ret->ocur = XML_ELEMENT_CONTENT_ONCE;
741
0
    if (name != NULL) {
742
0
        int l;
743
0
  const xmlChar *tmp;
744
745
0
  tmp = xmlSplitQName3(name, &l);
746
0
  if (tmp == NULL) {
747
0
      if (dict == NULL)
748
0
    ret->name = xmlStrdup(name);
749
0
      else
750
0
          ret->name = xmlDictLookup(dict, name, -1);
751
0
  } else {
752
0
      if (dict == NULL) {
753
0
    ret->prefix = xmlStrndup(name, l);
754
0
    ret->name = xmlStrdup(tmp);
755
0
      } else {
756
0
          ret->prefix = xmlDictLookup(dict, name, l);
757
0
    ret->name = xmlDictLookup(dict, tmp, -1);
758
0
      }
759
0
            if (ret->prefix == NULL)
760
0
                goto error;
761
0
  }
762
0
        if (ret->name == NULL)
763
0
            goto error;
764
0
    }
765
0
    return(ret);
766
767
0
error:
768
0
    xmlFreeDocElementContent(doc, ret);
769
0
    return(NULL);
770
0
}
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
224
xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
912
224
    xmlDictPtr dict = NULL;
913
224
    size_t depth = 0;
914
915
224
    if (cur == NULL)
916
224
        return;
917
0
    if (doc != NULL)
918
0
        dict = doc->dict;
919
920
0
    while (1) {
921
0
        xmlElementContentPtr parent;
922
923
0
        while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
924
0
            cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
925
0
            depth += 1;
926
0
        }
927
928
0
  switch (cur->type) {
929
0
      case XML_ELEMENT_CONTENT_PCDATA:
930
0
      case XML_ELEMENT_CONTENT_ELEMENT:
931
0
      case XML_ELEMENT_CONTENT_SEQ:
932
0
      case XML_ELEMENT_CONTENT_OR:
933
0
    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
0
  }
940
0
  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
0
  } else {
946
0
      if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
947
0
      if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
948
0
  }
949
0
        parent = cur->parent;
950
0
        if ((depth == 0) || (parent == NULL)) {
951
0
            xmlFree(cur);
952
0
            break;
953
0
        }
954
0
        if (cur == parent->c1)
955
0
            parent->c1 = NULL;
956
0
        else
957
0
            parent->c2 = NULL;
958
0
  xmlFree(cur);
959
960
0
        if (parent->c2 != NULL) {
961
0
      cur = parent->c2;
962
0
        } else {
963
0
            depth -= 1;
964
0
            cur = parent;
965
0
        }
966
0
    }
967
0
}
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
224
xmlFreeElement(xmlElementPtr elem) {
1119
224
    if (elem == NULL) return;
1120
224
    xmlUnlinkNode((xmlNodePtr) elem);
1121
224
    xmlFreeDocElementContent(elem->doc, elem->content);
1122
224
    if (elem->name != NULL)
1123
224
  xmlFree((xmlChar *) elem->name);
1124
224
    if (elem->prefix != NULL)
1125
0
  xmlFree((xmlChar *) elem->prefix);
1126
#ifdef LIBXML_REGEXP_ENABLED
1127
    if (elem->contModel != NULL)
1128
  xmlRegFreeRegexp(elem->contModel);
1129
#endif
1130
224
    xmlFree(elem);
1131
224
}
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
#ifdef LIBXML_VALID_ENABLED
1250
      /*
1251
       * The element is already defined in this DTD.
1252
       */
1253
      xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1254
                      "Redefinition of element %s\n",
1255
          name, NULL, NULL);
1256
#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
224
xmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) {
1346
224
    xmlFreeElement((xmlElementPtr) elem);
1347
224
}
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
224
xmlFreeElementTable(xmlElementTablePtr table) {
1359
224
    xmlHashFree(table, xmlFreeElementTableEntry);
1360
224
}
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
0
xmlCreateEnumeration(const xmlChar *name) {
1494
0
    xmlEnumerationPtr ret;
1495
1496
0
    ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1497
0
    if (ret == NULL)
1498
0
        return(NULL);
1499
0
    memset(ret, 0, sizeof(xmlEnumeration));
1500
1501
0
    if (name != NULL) {
1502
0
        ret->name = xmlStrdup(name);
1503
0
        if (ret->name == NULL) {
1504
0
            xmlFree(ret);
1505
0
            return(NULL);
1506
0
        }
1507
0
    }
1508
1509
0
    return(ret);
1510
0
}
1511
1512
/**
1513
 * xmlFreeEnumeration:
1514
 * @cur:  the tree to free.
1515
 *
1516
 * free an enumeration attribute node (recursive).
1517
 */
1518
void
1519
0
xmlFreeEnumeration(xmlEnumerationPtr cur) {
1520
0
    while (cur != NULL) {
1521
0
        xmlEnumerationPtr next = cur->next;
1522
1523
0
        xmlFree((xmlChar *) cur->name);
1524
0
        xmlFree(cur);
1525
1526
0
        cur = next;
1527
0
    }
1528
0
}
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
xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1581
    xmlAttributePtr cur;
1582
    int ret = 0;
1583
1584
    if (elem == NULL) return(0);
1585
    cur = elem->attributes;
1586
    while (cur != NULL) {
1587
        if (cur->atype == XML_ATTRIBUTE_ID) {
1588
      ret ++;
1589
      if ((ret > 1) && (err))
1590
    xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1591
         "Element %s has too many ID attributes defined : %s\n",
1592
           elem->name, cur->name, NULL);
1593
  }
1594
  cur = cur->nexth;
1595
    }
1596
    return(ret);
1597
}
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
1.29k
xmlFreeAttribute(xmlAttributePtr attr) {
1608
1.29k
    xmlDictPtr dict;
1609
1610
1.29k
    if (attr == NULL) return;
1611
1.29k
    if (attr->doc != NULL)
1612
1.29k
  dict = attr->doc->dict;
1613
0
    else
1614
0
  dict = NULL;
1615
1.29k
    xmlUnlinkNode((xmlNodePtr) attr);
1616
1.29k
    if (attr->tree != NULL)
1617
0
        xmlFreeEnumeration(attr->tree);
1618
1.29k
    if (dict) {
1619
1.29k
        if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1620
0
      xmlFree((xmlChar *) attr->elem);
1621
1.29k
        if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1622
0
      xmlFree((xmlChar *) attr->name);
1623
1.29k
        if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1624
0
      xmlFree((xmlChar *) attr->prefix);
1625
1.29k
        if ((attr->defaultValue != NULL) &&
1626
1.29k
      (!xmlDictOwns(dict, attr->defaultValue)))
1627
0
      xmlFree((xmlChar *) attr->defaultValue);
1628
1.29k
    } 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
1.29k
    xmlFree(attr);
1639
1.29k
}
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
1.29k
        const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1667
1.29k
    xmlAttributePtr ret = NULL;
1668
1.29k
    xmlAttributeTablePtr table;
1669
1.29k
    xmlElementPtr elemDef;
1670
1.29k
    xmlDictPtr dict = NULL;
1671
1.29k
    int res;
1672
1673
1.29k
    if (dtd == NULL) {
1674
0
  xmlFreeEnumeration(tree);
1675
0
  return(NULL);
1676
0
    }
1677
1.29k
    if (name == NULL) {
1678
0
  xmlFreeEnumeration(tree);
1679
0
  return(NULL);
1680
0
    }
1681
1.29k
    if (elem == NULL) {
1682
0
  xmlFreeEnumeration(tree);
1683
0
  return(NULL);
1684
0
    }
1685
1.29k
    if (dtd->doc != NULL)
1686
1.29k
  dict = dtd->doc->dict;
1687
1688
#ifdef LIBXML_VALID_ENABLED
1689
    /*
1690
     * Check the type and possibly the default value.
1691
     */
1692
    switch (type) {
1693
        case XML_ATTRIBUTE_CDATA:
1694
      break;
1695
        case XML_ATTRIBUTE_ID:
1696
      break;
1697
        case XML_ATTRIBUTE_IDREF:
1698
      break;
1699
        case XML_ATTRIBUTE_IDREFS:
1700
      break;
1701
        case XML_ATTRIBUTE_ENTITY:
1702
      break;
1703
        case XML_ATTRIBUTE_ENTITIES:
1704
      break;
1705
        case XML_ATTRIBUTE_NMTOKEN:
1706
      break;
1707
        case XML_ATTRIBUTE_NMTOKENS:
1708
      break;
1709
        case XML_ATTRIBUTE_ENUMERATION:
1710
      break;
1711
        case XML_ATTRIBUTE_NOTATION:
1712
      break;
1713
  default:
1714
      xmlErrValid(ctxt, XML_ERR_ARGUMENT,
1715
        "xmlAddAttributeDecl: invalid type\n", NULL);
1716
      xmlFreeEnumeration(tree);
1717
      return(NULL);
1718
    }
1719
    if ((defaultValue != NULL) &&
1720
        (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
1721
  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1722
                  "Attribute %s of %s: invalid default value\n",
1723
                  elem, name, defaultValue);
1724
  defaultValue = NULL;
1725
  if (ctxt != NULL)
1726
      ctxt->valid = 0;
1727
    }
1728
#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
1.29k
    if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1735
1.29k
  (dtd->doc->intSubset != NULL) &&
1736
1.29k
  (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
1.29k
    table = (xmlAttributeTablePtr) dtd->attributes;
1748
1.29k
    if (table == NULL) {
1749
224
        table = xmlHashCreateDict(0, dict);
1750
224
  dtd->attributes = (void *) table;
1751
224
    }
1752
1.29k
    if (table == NULL)
1753
0
        goto mem_error;
1754
1755
1.29k
    ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1756
1.29k
    if (ret == NULL)
1757
0
        goto mem_error;
1758
1.29k
    memset(ret, 0, sizeof(xmlAttribute));
1759
1.29k
    ret->type = XML_ATTRIBUTE_DECL;
1760
1761
    /*
1762
     * fill the structure.
1763
     */
1764
1.29k
    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
1.29k
    ret->doc = dtd->doc;
1771
1.29k
    if (dict) {
1772
1.29k
  ret->name = xmlDictLookup(dict, name, -1);
1773
1.29k
  ret->elem = xmlDictLookup(dict, elem, -1);
1774
1.29k
    } else {
1775
0
  ret->name = xmlStrdup(name);
1776
0
  ret->elem = xmlStrdup(elem);
1777
0
    }
1778
1.29k
    if ((ret->name == NULL) || (ret->elem == NULL))
1779
0
        goto mem_error;
1780
1.29k
    if (ns != NULL) {
1781
5
        if (dict)
1782
5
            ret->prefix = xmlDictLookup(dict, ns, -1);
1783
0
        else
1784
0
            ret->prefix = xmlStrdup(ns);
1785
5
        if (ret->prefix == NULL)
1786
0
            goto mem_error;
1787
5
    }
1788
1.29k
    ret->def = def;
1789
1.29k
    ret->tree = tree;
1790
1.29k
    tree = NULL;
1791
1.29k
    if (defaultValue != NULL) {
1792
28
        if (dict)
1793
28
      ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
1794
0
  else
1795
0
      ret->defaultValue = xmlStrdup(defaultValue);
1796
28
        if (ret->defaultValue == NULL)
1797
0
            goto mem_error;
1798
28
    }
1799
1800
1.29k
    elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem);
1801
1.29k
    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
1.29k
    res = xmlHashAdd3(table, ret->name, ret->prefix, ret->elem, ret);
1809
1.29k
    if (res <= 0) {
1810
1.05k
        if (res < 0)
1811
0
            goto mem_error;
1812
#ifdef LIBXML_VALID_ENABLED
1813
        /*
1814
         * The attribute is already defined in this DTD.
1815
         */
1816
        xmlErrValidWarning(ctxt, (xmlNodePtr) dtd,
1817
                XML_DTD_ATTRIBUTE_REDEFINED,
1818
                "Attribute %s of element %s: already defined\n",
1819
                name, elem, NULL);
1820
#endif /* LIBXML_VALID_ENABLED */
1821
1.05k
  xmlFreeAttribute(ret);
1822
1.05k
  return(NULL);
1823
1.05k
    }
1824
1825
    /*
1826
     * Validity Check:
1827
     * Multiple ID per element
1828
     */
1829
#ifdef LIBXML_VALID_ENABLED
1830
    if ((type == XML_ATTRIBUTE_ID) &&
1831
        (xmlScanIDAttributeDecl(ctxt, elemDef, 1) != 0)) {
1832
        xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
1833
       "Element %s has too may ID attributes defined : %s\n",
1834
               elem, name, NULL);
1835
        if (ctxt != NULL)
1836
            ctxt->valid = 0;
1837
    }
1838
#endif /* LIBXML_VALID_ENABLED */
1839
1840
    /*
1841
     * Insert namespace default def first they need to be
1842
     * processed first.
1843
     */
1844
240
    if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1845
240
        ((ret->prefix != NULL &&
1846
236
         (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1847
4
        ret->nexth = elemDef->attributes;
1848
4
        elemDef->attributes = ret;
1849
236
    } else {
1850
236
        xmlAttributePtr tmp = elemDef->attributes;
1851
1852
248
        while ((tmp != NULL) &&
1853
248
               ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1854
28
                ((ret->prefix != NULL &&
1855
16
                 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1856
16
            if (tmp->nexth == NULL)
1857
4
                break;
1858
12
            tmp = tmp->nexth;
1859
12
        }
1860
236
        if (tmp != NULL) {
1861
16
            ret->nexth = tmp->nexth;
1862
16
            tmp->nexth = ret;
1863
220
        } else {
1864
220
            ret->nexth = elemDef->attributes;
1865
220
            elemDef->attributes = ret;
1866
220
        }
1867
236
    }
1868
1869
    /*
1870
     * Link it to the DTD
1871
     */
1872
240
    ret->parent = dtd;
1873
240
    if (dtd->last == NULL) {
1874
224
  dtd->children = dtd->last = (xmlNodePtr) ret;
1875
224
    } else {
1876
16
        dtd->last->next = (xmlNodePtr) ret;
1877
16
  ret->prev = dtd->last;
1878
16
  dtd->last = (xmlNodePtr) ret;
1879
16
    }
1880
240
    return(ret);
1881
1882
0
mem_error:
1883
0
    xmlVErrMemory(ctxt);
1884
0
    xmlFreeEnumeration(tree);
1885
0
    xmlFreeAttribute(ret);
1886
0
    return(NULL);
1887
1.29k
}
1888
1889
static void
1890
240
xmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) {
1891
240
    xmlFreeAttribute((xmlAttributePtr) attr);
1892
240
}
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
224
xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1904
224
    xmlHashFree(table, xmlFreeAttributeTableEntry);
1905
224
}
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
#ifdef LIBXML_VALID_ENABLED
2136
        xmlErrValid(ctxt, XML_DTD_NOTATION_REDEFINED,
2137
                    "xmlAddNotationDecl: %s already defined\n",
2138
                    (const char *) name);
2139
#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
510
  if ((str) && ((!dict) ||       \
2283
510
      (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))  \
2284
510
      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
510
xmlFreeID(xmlIDPtr id) {
2306
510
    xmlDictPtr dict = NULL;
2307
2308
510
    if (id == NULL) return;
2309
2310
510
    if (id->doc != NULL)
2311
510
        dict = id->doc->dict;
2312
2313
510
    if (id->value != NULL)
2314
510
  DICT_FREE(id->value)
2315
510
    if (id->name != NULL)
2316
0
  DICT_FREE(id->name)
2317
510
    if (id->attr != NULL) {
2318
510
        id->attr->id = NULL;
2319
510
        id->attr->atype = 0;
2320
510
    }
2321
2322
510
    xmlFree(id);
2323
510
}
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
8.06k
xmlAddIDInternal(xmlAttrPtr attr, const xmlChar *value, xmlIDPtr *idPtr) {
2339
8.06k
    xmlDocPtr doc;
2340
8.06k
    xmlIDPtr id;
2341
8.06k
    xmlIDTablePtr table;
2342
8.06k
    int ret;
2343
2344
8.06k
    if (idPtr != NULL)
2345
8.06k
        *idPtr = NULL;
2346
8.06k
    if ((value == NULL) || (value[0] == 0))
2347
0
  return(0);
2348
8.06k
    if (attr == NULL)
2349
0
  return(0);
2350
2351
8.06k
    doc = attr->doc;
2352
8.06k
    if (doc == NULL)
2353
0
        return(0);
2354
2355
    /*
2356
     * Create the ID table if needed.
2357
     */
2358
8.06k
    table = (xmlIDTablePtr) doc->ids;
2359
8.06k
    if (table == NULL)  {
2360
36
        doc->ids = table = xmlHashCreateDict(0, doc->dict);
2361
36
        if (table == NULL)
2362
0
            return(-1);
2363
8.03k
    } else {
2364
8.03k
        id = xmlHashLookup(table, value);
2365
8.03k
        if (id != NULL)
2366
7.55k
            return(0);
2367
8.03k
    }
2368
2369
510
    id = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2370
510
    if (id == NULL)
2371
0
  return(-1);
2372
510
    memset(id, 0, sizeof(*id));
2373
2374
    /*
2375
     * fill the structure.
2376
     */
2377
510
    id->doc = doc;
2378
510
    id->value = xmlStrdup(value);
2379
510
    if (id->value == NULL) {
2380
0
        xmlFreeID(id);
2381
0
        return(-1);
2382
0
    }
2383
2384
510
    if (attr->id != NULL)
2385
0
        xmlRemoveID(doc, attr);
2386
2387
510
    if (xmlHashAddEntry(table, value, id) < 0) {
2388
0
  xmlFreeID(id);
2389
0
  return(-1);
2390
0
    }
2391
2392
510
    ret = 1;
2393
510
    if (idPtr != NULL)
2394
510
        *idPtr = id;
2395
2396
510
    id->attr = attr;
2397
510
    id->lineno = xmlGetLineNo(attr->parent);
2398
510
    attr->atype = XML_ATTRIBUTE_ID;
2399
510
    attr->id = id;
2400
2401
510
    return(ret);
2402
510
}
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
0
xmlAddIDSafe(xmlAttrPtr attr, const xmlChar *value) {
2418
0
    return(xmlAddIDInternal(attr, value, NULL));
2419
0
}
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
8.06k
         xmlAttrPtr attr) {
2435
8.06k
    xmlIDPtr id;
2436
8.06k
    int res;
2437
2438
8.06k
    if ((attr == NULL) || (doc != attr->doc))
2439
0
        return(NULL);
2440
2441
8.06k
    res = xmlAddIDInternal(attr, value, &id);
2442
8.06k
    if (res < 0) {
2443
0
        xmlVErrMemory(ctxt);
2444
0
    }
2445
#ifdef LIBXML_VALID_ENABLED
2446
    else if (res == 0) {
2447
        if (ctxt != NULL) {
2448
            /*
2449
             * The id is already defined in this DTD.
2450
             */
2451
            xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2452
                            "ID %s already defined\n", value, NULL, NULL);
2453
        }
2454
    }
2455
#endif /* LIBXML_VALID_ENABLED */
2456
2457
8.06k
    return(id);
2458
8.06k
}
2459
2460
static void
2461
510
xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) {
2462
510
    xmlFreeID((xmlIDPtr) id);
2463
510
}
2464
2465
/**
2466
 * xmlFreeIDTable:
2467
 * @table:  An id table
2468
 *
2469
 * Deallocate the memory used by an ID hash table.
2470
 */
2471
void
2472
36
xmlFreeIDTable(xmlIDTablePtr table) {
2473
36
    xmlHashFree(table, xmlFreeIDTableEntry);
2474
36
}
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
10.7k
xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2492
10.7k
    if ((attr == NULL) || (attr->name == NULL))
2493
0
        return(0);
2494
2495
10.7k
    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
10.7k
    } else {
2506
10.7k
  xmlAttributePtr attrDecl = NULL;
2507
10.7k
  xmlChar felem[50];
2508
10.7k
  xmlChar *fullelemname;
2509
10.7k
        const xmlChar *aprefix;
2510
2511
10.7k
        if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2512
10.7k
            (!strcmp((char *) attr->name, "id")) &&
2513
10.7k
            (!strcmp((char *) attr->ns->prefix, "xml")))
2514
0
            return(1);
2515
2516
10.7k
        if ((doc == NULL) ||
2517
10.7k
            ((doc->intSubset == NULL) && (doc->extSubset == NULL)))
2518
10.6k
            return(0);
2519
2520
109
        if ((elem == NULL) ||
2521
109
            (elem->type != XML_ELEMENT_NODE) ||
2522
109
            (elem->name == NULL))
2523
0
            return(0);
2524
2525
109
  fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2526
0
      xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2527
109
      (xmlChar *)elem->name;
2528
109
        if (fullelemname == NULL)
2529
0
            return(-1);
2530
2531
109
        aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
2532
2533
109
  if (fullelemname != NULL) {
2534
109
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullelemname,
2535
109
                              attr->name, aprefix);
2536
109
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
2537
0
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullelemname,
2538
0
                attr->name, aprefix);
2539
109
  }
2540
2541
109
  if ((fullelemname != felem) && (fullelemname != elem->name))
2542
0
      xmlFree(fullelemname);
2543
2544
109
        if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2545
0
      return(1);
2546
109
    }
2547
2548
109
    return(0);
2549
10.7k
}
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
10.7k
xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2832
10.7k
    if (attr == NULL)
2833
0
        return(0);
2834
10.7k
    if (doc == NULL) {
2835
0
        doc = attr->doc;
2836
0
  if (doc == NULL) return(0);
2837
0
    }
2838
2839
10.7k
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2840
10.6k
        return(0);
2841
10.6k
    } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2842
        /* TODO @@@ */
2843
0
        return(0);
2844
109
    } else {
2845
109
        xmlAttributePtr attrDecl;
2846
109
        const xmlChar *aprefix;
2847
2848
109
        if (elem == NULL) return(0);
2849
109
        aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
2850
109
        attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name, attr->name,
2851
109
                                      aprefix);
2852
109
        if ((attrDecl == NULL) && (doc->extSubset != NULL))
2853
0
            attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name, attr->name,
2854
0
                                          aprefix);
2855
2856
109
  if ((attrDecl != NULL) &&
2857
109
      (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2858
0
       attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2859
0
  return(1);
2860
109
    }
2861
109
    return(0);
2862
10.7k
}
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
1.29k
xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name) {
3007
1.29k
    xmlElementTablePtr table;
3008
1.29k
    xmlElementPtr cur = NULL;
3009
1.29k
    const xmlChar *localName;
3010
1.29k
    xmlChar *prefix = NULL;
3011
3012
1.29k
    if (dtd == NULL) return(NULL);
3013
3014
    /*
3015
     * Create the Element table if needed.
3016
     */
3017
1.29k
    if (dtd->elements == NULL) {
3018
224
  xmlDictPtr dict = NULL;
3019
3020
224
  if (dtd->doc != NULL)
3021
224
      dict = dtd->doc->dict;
3022
3023
224
  dtd->elements = xmlHashCreateDict(0, dict);
3024
224
  if (dtd->elements == NULL)
3025
0
            goto mem_error;
3026
224
    }
3027
1.29k
    table = (xmlElementTablePtr) dtd->elements;
3028
3029
1.29k
    localName = xmlSplitQName4(name, &prefix);
3030
1.29k
    if (localName == NULL)
3031
0
        goto mem_error;
3032
1.29k
    cur = xmlHashLookup2(table, localName, prefix);
3033
1.29k
    if (cur == NULL) {
3034
224
  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3035
224
  if (cur == NULL)
3036
0
            goto mem_error;
3037
224
  memset(cur, 0, sizeof(xmlElement));
3038
224
  cur->type = XML_ELEMENT_DECL;
3039
224
        cur->doc = dtd->doc;
3040
3041
  /*
3042
   * fill the structure.
3043
   */
3044
224
  cur->name = xmlStrdup(localName);
3045
224
        if (cur->name == NULL)
3046
0
            goto mem_error;
3047
224
  cur->prefix = prefix;
3048
224
        prefix = NULL;
3049
224
  cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3050
3051
224
  if (xmlHashAdd2(table, localName, cur->prefix, cur) <= 0)
3052
0
            goto mem_error;
3053
224
    }
3054
3055
1.29k
    if (prefix != NULL)
3056
0
        xmlFree(prefix);
3057
1.29k
    return(cur);
3058
3059
0
mem_error:
3060
0
    xmlVErrMemory(ctxt);
3061
0
    xmlFree(prefix);
3062
0
    xmlFreeElement(cur);
3063
0
    return(NULL);
3064
1.29k
}
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
218
            const xmlChar *prefix) {
3141
218
    xmlAttributeTablePtr table;
3142
3143
218
    if (dtd == NULL) return(NULL);
3144
218
    if (dtd->attributes == NULL) return(NULL);
3145
178
    table = (xmlAttributeTablePtr) dtd->attributes;
3146
3147
178
    return(xmlHashLookup3(table, name, prefix, elem));
3148
218
}
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
                       const xmlChar *notationName) {
3189
    xmlNotationPtr notaDecl;
3190
    if ((doc == NULL) || (doc->intSubset == NULL) ||
3191
        (notationName == NULL)) return(-1);
3192
3193
    notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3194
    if ((notaDecl == NULL) && (doc->extSubset != NULL))
3195
  notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3196
3197
    if (notaDecl == NULL) {
3198
  xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3199
                  "NOTATION %s is not declared\n",
3200
            notationName, NULL, NULL);
3201
  return(0);
3202
    }
3203
    return(1);
3204
}
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
xmlValidNormalizeString(xmlChar *str) {
3255
    xmlChar *dst;
3256
    const xmlChar *src;
3257
3258
    if (str == NULL)
3259
        return;
3260
    src = str;
3261
    dst = str;
3262
3263
    while (*src == 0x20) src++;
3264
    while (*src != 0) {
3265
  if (*src == 0x20) {
3266
      while (*src == 0x20) src++;
3267
      if (*src != 0)
3268
    *dst++ = 0x20;
3269
  } else {
3270
      *dst++ = *src++;
3271
  }
3272
    }
3273
    *dst = 0;
3274
}
3275
3276
static int
3277
xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3278
    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
  if (((c >= 'a') && (c <= 'z')) ||
3284
      ((c >= 'A') && (c <= 'Z')) ||
3285
      (c == '_') || (c == ':') ||
3286
      ((c >= 0xC0) && (c <= 0xD6)) ||
3287
      ((c >= 0xD8) && (c <= 0xF6)) ||
3288
      ((c >= 0xF8) && (c <= 0x2FF)) ||
3289
      ((c >= 0x370) && (c <= 0x37D)) ||
3290
      ((c >= 0x37F) && (c <= 0x1FFF)) ||
3291
      ((c >= 0x200C) && (c <= 0x200D)) ||
3292
      ((c >= 0x2070) && (c <= 0x218F)) ||
3293
      ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3294
      ((c >= 0x3001) && (c <= 0xD7FF)) ||
3295
      ((c >= 0xF900) && (c <= 0xFDCF)) ||
3296
      ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3297
      ((c >= 0x10000) && (c <= 0xEFFFF)))
3298
      return(1);
3299
    } else {
3300
        if (IS_LETTER(c) || (c == '_') || (c == ':'))
3301
      return(1);
3302
    }
3303
    return(0);
3304
}
3305
3306
static int
3307
xmlIsDocNameChar(xmlDocPtr doc, int c) {
3308
    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
  if (((c >= 'a') && (c <= 'z')) ||
3314
      ((c >= 'A') && (c <= 'Z')) ||
3315
      ((c >= '0') && (c <= '9')) || /* !start */
3316
      (c == '_') || (c == ':') ||
3317
      (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3318
      ((c >= 0xC0) && (c <= 0xD6)) ||
3319
      ((c >= 0xD8) && (c <= 0xF6)) ||
3320
      ((c >= 0xF8) && (c <= 0x2FF)) ||
3321
      ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3322
      ((c >= 0x370) && (c <= 0x37D)) ||
3323
      ((c >= 0x37F) && (c <= 0x1FFF)) ||
3324
      ((c >= 0x200C) && (c <= 0x200D)) ||
3325
      ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3326
      ((c >= 0x2070) && (c <= 0x218F)) ||
3327
      ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3328
      ((c >= 0x3001) && (c <= 0xD7FF)) ||
3329
      ((c >= 0xF900) && (c <= 0xFDCF)) ||
3330
      ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3331
      ((c >= 0x10000) && (c <= 0xEFFFF)))
3332
       return(1);
3333
    } else {
3334
        if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3335
            (c == '.') || (c == '-') ||
3336
      (c == '_') || (c == ':') ||
3337
      (IS_COMBINING(c)) ||
3338
      (IS_EXTENDER(c)))
3339
      return(1);
3340
    }
3341
    return(0);
3342
}
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
xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3356
    const xmlChar *cur;
3357
    int val, len;
3358
3359
    if (value == NULL) return(0);
3360
    cur = value;
3361
    val = xmlStringCurrentChar(NULL, cur, &len);
3362
    cur += len;
3363
    if (!xmlIsDocNameStartChar(doc, val))
3364
  return(0);
3365
3366
    val = xmlStringCurrentChar(NULL, cur, &len);
3367
    cur += len;
3368
    while (xmlIsDocNameChar(doc, val)) {
3369
  val = xmlStringCurrentChar(NULL, cur, &len);
3370
  cur += len;
3371
    }
3372
3373
    if (val != 0) return(0);
3374
3375
    return(1);
3376
}
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
xmlValidateNameValue(const xmlChar *value) {
3389
    return(xmlValidateNameValueInternal(NULL, value));
3390
}
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
xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3404
    const xmlChar *cur;
3405
    int val, len;
3406
3407
    if (value == NULL) return(0);
3408
    cur = value;
3409
    val = xmlStringCurrentChar(NULL, cur, &len);
3410
    cur += len;
3411
3412
    if (!xmlIsDocNameStartChar(doc, val))
3413
  return(0);
3414
3415
    val = xmlStringCurrentChar(NULL, cur, &len);
3416
    cur += len;
3417
    while (xmlIsDocNameChar(doc, val)) {
3418
  val = xmlStringCurrentChar(NULL, cur, &len);
3419
  cur += len;
3420
    }
3421
3422
    /* Should not test IS_BLANK(val) here -- see erratum E20*/
3423
    while (val == 0x20) {
3424
  while (val == 0x20) {
3425
      val = xmlStringCurrentChar(NULL, cur, &len);
3426
      cur += len;
3427
  }
3428
3429
  if (!xmlIsDocNameStartChar(doc, val))
3430
      return(0);
3431
3432
  val = xmlStringCurrentChar(NULL, cur, &len);
3433
  cur += len;
3434
3435
  while (xmlIsDocNameChar(doc, val)) {
3436
      val = xmlStringCurrentChar(NULL, cur, &len);
3437
      cur += len;
3438
  }
3439
    }
3440
3441
    if (val != 0) return(0);
3442
3443
    return(1);
3444
}
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
xmlValidateNamesValue(const xmlChar *value) {
3457
    return(xmlValidateNamesValueInternal(NULL, value));
3458
}
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
xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3474
    const xmlChar *cur;
3475
    int val, len;
3476
3477
    if (value == NULL) return(0);
3478
    cur = value;
3479
    val = xmlStringCurrentChar(NULL, cur, &len);
3480
    cur += len;
3481
3482
    if (!xmlIsDocNameChar(doc, val))
3483
  return(0);
3484
3485
    val = xmlStringCurrentChar(NULL, cur, &len);
3486
    cur += len;
3487
    while (xmlIsDocNameChar(doc, val)) {
3488
  val = xmlStringCurrentChar(NULL, cur, &len);
3489
  cur += len;
3490
    }
3491
3492
    if (val != 0) return(0);
3493
3494
    return(1);
3495
}
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
xmlValidateNmtokenValue(const xmlChar *value) {
3510
    return(xmlValidateNmtokenValueInternal(NULL, value));
3511
}
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
xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3527
    const xmlChar *cur;
3528
    int val, len;
3529
3530
    if (value == NULL) return(0);
3531
    cur = value;
3532
    val = xmlStringCurrentChar(NULL, cur, &len);
3533
    cur += len;
3534
3535
    while (IS_BLANK(val)) {
3536
  val = xmlStringCurrentChar(NULL, cur, &len);
3537
  cur += len;
3538
    }
3539
3540
    if (!xmlIsDocNameChar(doc, val))
3541
  return(0);
3542
3543
    while (xmlIsDocNameChar(doc, val)) {
3544
  val = xmlStringCurrentChar(NULL, cur, &len);
3545
  cur += len;
3546
    }
3547
3548
    /* Should not test IS_BLANK(val) here -- see erratum E20*/
3549
    while (val == 0x20) {
3550
  while (val == 0x20) {
3551
      val = xmlStringCurrentChar(NULL, cur, &len);
3552
      cur += len;
3553
  }
3554
  if (val == 0) return(1);
3555
3556
  if (!xmlIsDocNameChar(doc, val))
3557
      return(0);
3558
3559
  val = xmlStringCurrentChar(NULL, cur, &len);
3560
  cur += len;
3561
3562
  while (xmlIsDocNameChar(doc, val)) {
3563
      val = xmlStringCurrentChar(NULL, cur, &len);
3564
      cur += len;
3565
  }
3566
    }
3567
3568
    if (val != 0) return(0);
3569
3570
    return(1);
3571
}
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
xmlValidateNmtokensValue(const xmlChar *value) {
3586
    return(xmlValidateNmtokensValueInternal(NULL, value));
3587
}
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
                         xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3609
    int ret = 1;
3610
3611
    return(ret);
3612
}
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
                                  const xmlChar *value) {
3628
    switch (type) {
3629
  case XML_ATTRIBUTE_ENTITIES:
3630
  case XML_ATTRIBUTE_IDREFS:
3631
      return(xmlValidateNamesValueInternal(doc, value));
3632
  case XML_ATTRIBUTE_ENTITY:
3633
  case XML_ATTRIBUTE_IDREF:
3634
  case XML_ATTRIBUTE_ID:
3635
  case XML_ATTRIBUTE_NOTATION:
3636
      return(xmlValidateNameValueInternal(doc, value));
3637
  case XML_ATTRIBUTE_NMTOKENS:
3638
  case XML_ATTRIBUTE_ENUMERATION:
3639
      return(xmlValidateNmtokensValueInternal(doc, value));
3640
  case XML_ATTRIBUTE_NMTOKEN:
3641
      return(xmlValidateNmtokenValueInternal(doc, value));
3642
        case XML_ATTRIBUTE_CDATA:
3643
      break;
3644
    }
3645
    return(1);
3646
}
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
xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3676
    return(xmlValidateAttributeValueInternal(NULL, type, value));
3677
}
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
      const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3711
    int ret = 1;
3712
    switch (type) {
3713
  case XML_ATTRIBUTE_IDREFS:
3714
  case XML_ATTRIBUTE_IDREF:
3715
  case XML_ATTRIBUTE_ID:
3716
  case XML_ATTRIBUTE_NMTOKENS:
3717
  case XML_ATTRIBUTE_ENUMERATION:
3718
  case XML_ATTRIBUTE_NMTOKEN:
3719
        case XML_ATTRIBUTE_CDATA:
3720
      break;
3721
  case XML_ATTRIBUTE_ENTITY: {
3722
      xmlEntityPtr ent;
3723
3724
      ent = xmlGetDocEntity(doc, value);
3725
      /* yeah it's a bit messy... */
3726
      if ((ent == NULL) && (doc->standalone == 1)) {
3727
    doc->standalone = 0;
3728
    ent = xmlGetDocEntity(doc, value);
3729
      }
3730
      if (ent == NULL) {
3731
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3732
        XML_DTD_UNKNOWN_ENTITY,
3733
   "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3734
           name, value, NULL);
3735
    ret = 0;
3736
      } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3737
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3738
        XML_DTD_ENTITY_TYPE,
3739
   "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3740
           name, value, NULL);
3741
    ret = 0;
3742
      }
3743
      break;
3744
        }
3745
  case XML_ATTRIBUTE_ENTITIES: {
3746
      xmlChar *dup, *nam = NULL, *cur, save;
3747
      xmlEntityPtr ent;
3748
3749
      dup = xmlStrdup(value);
3750
      if (dup == NULL) {
3751
                xmlVErrMemory(ctxt);
3752
    return(0);
3753
            }
3754
      cur = dup;
3755
      while (*cur != 0) {
3756
    nam = cur;
3757
    while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
3758
    save = *cur;
3759
    *cur = 0;
3760
    ent = xmlGetDocEntity(doc, nam);
3761
    if (ent == NULL) {
3762
        xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3763
            XML_DTD_UNKNOWN_ENTITY,
3764
       "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3765
         name, nam, NULL);
3766
        ret = 0;
3767
    } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3768
        xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3769
            XML_DTD_ENTITY_TYPE,
3770
       "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3771
         name, nam, NULL);
3772
        ret = 0;
3773
    }
3774
    if (save == 0)
3775
        break;
3776
    *cur = save;
3777
    while (IS_BLANK_CH(*cur)) cur++;
3778
      }
3779
      xmlFree(dup);
3780
      break;
3781
  }
3782
  case XML_ATTRIBUTE_NOTATION: {
3783
      xmlNotationPtr nota;
3784
3785
      nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3786
      if ((nota == NULL) && (doc->extSubset != NULL))
3787
    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3788
3789
      if (nota == NULL) {
3790
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3791
                    XML_DTD_UNKNOWN_NOTATION,
3792
       "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3793
           name, value, NULL);
3794
    ret = 0;
3795
      }
3796
      break;
3797
        }
3798
    }
3799
    return(ret);
3800
}
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
       xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3831
    xmlChar *ret;
3832
    xmlAttributePtr attrDecl = NULL;
3833
    const xmlChar *localName;
3834
    xmlChar *prefix = NULL;
3835
    int extsubset = 0;
3836
3837
    if (doc == NULL) return(NULL);
3838
    if (elem == NULL) return(NULL);
3839
    if (name == NULL) return(NULL);
3840
    if (value == NULL) return(NULL);
3841
3842
    localName = xmlSplitQName4(name, &prefix);
3843
    if (localName == NULL)
3844
        goto mem_error;
3845
3846
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3847
  xmlChar buf[50];
3848
  xmlChar *elemname;
3849
3850
  elemname = xmlBuildQName(elem->name, elem->ns->prefix, buf, 50);
3851
  if (elemname == NULL)
3852
      goto mem_error;
3853
        if (doc->intSubset != NULL)
3854
            attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName,
3855
                                      prefix, elemname);
3856
  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3857
      attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName,
3858
                                      prefix, elemname);
3859
      if (attrDecl != NULL)
3860
    extsubset = 1;
3861
  }
3862
  if ((elemname != buf) && (elemname != elem->name))
3863
      xmlFree(elemname);
3864
    }
3865
    if ((attrDecl == NULL) && (doc->intSubset != NULL))
3866
  attrDecl = xmlHashLookup3(doc->intSubset->attributes, localName,
3867
                                  prefix, elem->name);
3868
    if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3869
  attrDecl = xmlHashLookup3(doc->extSubset->attributes, localName,
3870
                                  prefix, elem->name);
3871
  if (attrDecl != NULL)
3872
      extsubset = 1;
3873
    }
3874
3875
    if (attrDecl == NULL)
3876
  goto done;
3877
    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3878
  goto done;
3879
3880
    ret = xmlStrdup(value);
3881
    if (ret == NULL)
3882
  goto mem_error;
3883
    xmlValidNormalizeString(ret);
3884
    if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
3885
  xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
3886
"standalone: %s on %s value had to be normalized based on external subset declaration\n",
3887
         name, elem->name, NULL);
3888
  ctxt->valid = 0;
3889
    }
3890
3891
    xmlFree(prefix);
3892
    return(ret);
3893
3894
mem_error:
3895
    xmlVErrMemory(ctxt);
3896
3897
done:
3898
    xmlFree(prefix);
3899
    return(NULL);
3900
}
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
              const xmlChar *name, const xmlChar *value) {
3926
    xmlChar *ret;
3927
    xmlAttributePtr attrDecl = NULL;
3928
3929
    if (doc == NULL) return(NULL);
3930
    if (elem == NULL) return(NULL);
3931
    if (name == NULL) return(NULL);
3932
    if (value == NULL) return(NULL);
3933
3934
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3935
  xmlChar fn[50];
3936
  xmlChar *fullname;
3937
3938
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3939
  if (fullname == NULL)
3940
      return(NULL);
3941
  if ((fullname != fn) && (fullname != elem->name))
3942
      xmlFree(fullname);
3943
    }
3944
    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3945
    if ((attrDecl == NULL) && (doc->extSubset != NULL))
3946
  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3947
3948
    if (attrDecl == NULL)
3949
  return(NULL);
3950
    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3951
  return(NULL);
3952
3953
    ret = xmlStrdup(value);
3954
    if (ret == NULL)
3955
  return(NULL);
3956
    xmlValidNormalizeString(ret);
3957
    return(ret);
3958
}
3959
3960
static void
3961
xmlValidateAttributeIdCallback(void *payload, void *data,
3962
                         const xmlChar *name ATTRIBUTE_UNUSED) {
3963
    xmlAttributePtr attr = (xmlAttributePtr) payload;
3964
    int *count = (int *) data;
3965
    if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3966
}
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
                         xmlAttributePtr attr) {
3991
    int ret = 1;
3992
    int val;
3993
    CHECK_DTD;
3994
    if(attr == NULL) return(1);
3995
3996
    /* Attribute Default Legal */
3997
    /* Enumeration */
3998
    if (attr->defaultValue != NULL) {
3999
  val = xmlValidateAttributeValueInternal(doc, attr->atype,
4000
                                          attr->defaultValue);
4001
  if (val == 0) {
4002
      xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4003
         "Syntax of default value for attribute %s of %s is not valid\n",
4004
             attr->name, attr->elem, NULL);
4005
  }
4006
        ret &= val;
4007
    }
4008
4009
    /* ID Attribute Default */
4010
    if ((attr->atype == XML_ATTRIBUTE_ID)&&
4011
        (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4012
  (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4013
  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4014
          "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4015
         attr->name, attr->elem, NULL);
4016
  ret = 0;
4017
    }
4018
4019
    /* One ID per Element Type */
4020
    if (attr->atype == XML_ATTRIBUTE_ID) {
4021
        xmlElementPtr elem = NULL;
4022
        const xmlChar *elemLocalName;
4023
        xmlChar *elemPrefix;
4024
        int nbId;
4025
4026
        elemLocalName = xmlSplitQName4(attr->elem, &elemPrefix);
4027
        if (elemLocalName == NULL) {
4028
            xmlVErrMemory(ctxt);
4029
            return(0);
4030
        }
4031
4032
  /* the trick is that we parse DtD as their own internal subset */
4033
        if (doc->intSubset != NULL)
4034
            elem = xmlHashLookup2(doc->intSubset->elements,
4035
                                  elemLocalName, elemPrefix);
4036
  if (elem != NULL) {
4037
      nbId = xmlScanIDAttributeDecl(ctxt, elem, 0);
4038
  } else {
4039
      xmlAttributeTablePtr table;
4040
4041
      /*
4042
       * The attribute may be declared in the internal subset and the
4043
       * element in the external subset.
4044
       */
4045
      nbId = 0;
4046
      if (doc->intSubset != NULL) {
4047
    table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4048
    xmlHashScan3(table, NULL, NULL, attr->elem,
4049
           xmlValidateAttributeIdCallback, &nbId);
4050
      }
4051
  }
4052
  if (nbId > 1) {
4053
4054
      xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4055
       "Element %s has %d ID attribute defined in the internal subset : %s\n",
4056
       attr->elem, nbId, attr->name);
4057
            ret = 0;
4058
  } else if (doc->extSubset != NULL) {
4059
      int extId = 0;
4060
      elem = xmlHashLookup2(doc->extSubset->elements,
4061
                                  elemLocalName, elemPrefix);
4062
      if (elem != NULL) {
4063
    extId = xmlScanIDAttributeDecl(ctxt, elem, 0);
4064
      }
4065
      if (extId > 1) {
4066
    xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4067
       "Element %s has %d ID attribute defined in the external subset : %s\n",
4068
           attr->elem, extId, attr->name);
4069
                ret = 0;
4070
      } else if (extId + nbId > 1) {
4071
    xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4072
"Element %s has ID attributes defined in the internal and external subset : %s\n",
4073
           attr->elem, attr->name, NULL);
4074
                ret = 0;
4075
      }
4076
  }
4077
4078
        xmlFree(elemPrefix);
4079
    }
4080
4081
    /* Validity Constraint: Enumeration */
4082
    if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4083
        xmlEnumerationPtr tree = attr->tree;
4084
  while (tree != NULL) {
4085
      if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4086
      tree = tree->next;
4087
  }
4088
  if (tree == NULL) {
4089
      xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4090
"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4091
       attr->defaultValue, attr->name, attr->elem);
4092
      ret = 0;
4093
  }
4094
    }
4095
4096
    return(ret);
4097
}
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
                       xmlElementPtr elem) {
4120
    int ret = 1;
4121
    xmlElementPtr tst;
4122
    const xmlChar *localName;
4123
    xmlChar *prefix;
4124
4125
    CHECK_DTD;
4126
4127
    if (elem == NULL) return(1);
4128
4129
    /* No Duplicate Types */
4130
    if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4131
  xmlElementContentPtr cur, next;
4132
        const xmlChar *name;
4133
4134
  cur = elem->content;
4135
  while (cur != NULL) {
4136
      if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4137
      if (cur->c1 == NULL) break;
4138
      if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4139
    name = cur->c1->name;
4140
    next = cur->c2;
4141
    while (next != NULL) {
4142
        if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4143
            if ((xmlStrEqual(next->name, name)) &&
4144
          (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4145
          if (cur->c1->prefix == NULL) {
4146
        xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4147
       "Definition of %s has duplicate references of %s\n",
4148
               elem->name, name, NULL);
4149
          } else {
4150
        xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4151
       "Definition of %s has duplicate references of %s:%s\n",
4152
               elem->name, cur->c1->prefix, name);
4153
          }
4154
          ret = 0;
4155
      }
4156
      break;
4157
        }
4158
        if (next->c1 == NULL) break;
4159
        if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4160
        if ((xmlStrEqual(next->c1->name, name)) &&
4161
            (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4162
      if (cur->c1->prefix == NULL) {
4163
          xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4164
         "Definition of %s has duplicate references to %s\n",
4165
           elem->name, name, NULL);
4166
      } else {
4167
          xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4168
         "Definition of %s has duplicate references to %s:%s\n",
4169
           elem->name, cur->c1->prefix, name);
4170
      }
4171
      ret = 0;
4172
        }
4173
        next = next->c2;
4174
    }
4175
      }
4176
      cur = cur->c2;
4177
  }
4178
    }
4179
4180
    localName = xmlSplitQName4(elem->name, &prefix);
4181
    if (localName == NULL) {
4182
        xmlVErrMemory(ctxt);
4183
        return(0);
4184
    }
4185
4186
    /* VC: Unique Element Type Declaration */
4187
    if (doc->intSubset != NULL) {
4188
        tst = xmlHashLookup2(doc->intSubset->elements, localName, prefix);
4189
4190
        if ((tst != NULL ) && (tst != elem) &&
4191
            ((tst->prefix == elem->prefix) ||
4192
             (xmlStrEqual(tst->prefix, elem->prefix))) &&
4193
            (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4194
            xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4195
                            "Redefinition of element %s\n",
4196
                           elem->name, NULL, NULL);
4197
            ret = 0;
4198
        }
4199
    }
4200
    if (doc->extSubset != NULL) {
4201
        tst = xmlHashLookup2(doc->extSubset->elements, localName, prefix);
4202
4203
        if ((tst != NULL ) && (tst != elem) &&
4204
            ((tst->prefix == elem->prefix) ||
4205
             (xmlStrEqual(tst->prefix, elem->prefix))) &&
4206
            (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4207
            xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4208
                            "Redefinition of element %s\n",
4209
                           elem->name, NULL, NULL);
4210
            ret = 0;
4211
        }
4212
    }
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
    xmlFree(prefix);
4221
    return(ret);
4222
}
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
{
4255
    xmlAttributePtr attrDecl =  NULL;
4256
    const xmlChar *aprefix;
4257
    int val;
4258
    int ret = 1;
4259
4260
    CHECK_DTD;
4261
    if ((elem == NULL) || (elem->name == NULL)) return(0);
4262
    if ((attr == NULL) || (attr->name == NULL)) return(0);
4263
4264
    aprefix = (attr->ns != NULL) ? attr->ns->prefix : NULL;
4265
4266
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4267
  xmlChar fn[50];
4268
  xmlChar *fullname;
4269
4270
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4271
  if (fullname == NULL) {
4272
            xmlVErrMemory(ctxt);
4273
      return(0);
4274
        }
4275
        attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4276
                                      attr->name, aprefix);
4277
        if ((attrDecl == NULL) && (doc->extSubset != NULL))
4278
            attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4279
                                          attr->name, aprefix);
4280
  if ((fullname != fn) && (fullname != elem->name))
4281
      xmlFree(fullname);
4282
    }
4283
    if (attrDecl == NULL) {
4284
        attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4285
                                      attr->name, aprefix);
4286
        if ((attrDecl == NULL) && (doc->extSubset != NULL))
4287
            attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4288
                                          attr->name, aprefix);
4289
    }
4290
4291
4292
    /* Validity Constraint: Attribute Value Type */
4293
    if (attrDecl == NULL) {
4294
  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4295
         "No declaration for attribute %s of element %s\n",
4296
         attr->name, elem->name, NULL);
4297
  return(0);
4298
    }
4299
    if (attr->atype == XML_ATTRIBUTE_ID)
4300
        xmlRemoveID(doc, attr);
4301
    attr->atype = attrDecl->atype;
4302
4303
    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4304
    if (val == 0) {
4305
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4306
     "Syntax of value for attribute %s of %s is not valid\n",
4307
         attr->name, elem->name, NULL);
4308
        ret = 0;
4309
    }
4310
4311
    /* Validity constraint: Fixed Attribute Default */
4312
    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4313
  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4314
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4315
     "Value for attribute %s of %s is different from default \"%s\"\n",
4316
       attr->name, elem->name, attrDecl->defaultValue);
4317
      ret = 0;
4318
  }
4319
    }
4320
4321
    /* Validity Constraint: ID uniqueness */
4322
    if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4323
        if (xmlAddID(ctxt, doc, value, attr) == NULL)
4324
      ret = 0;
4325
    }
4326
4327
    if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4328
  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4329
        if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4330
      ret = 0;
4331
    }
4332
4333
    /* Validity Constraint: Notation Attributes */
4334
    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4335
        xmlEnumerationPtr tree = attrDecl->tree;
4336
        xmlNotationPtr nota;
4337
4338
        /* First check that the given NOTATION was declared */
4339
  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4340
  if (nota == NULL)
4341
      nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4342
4343
  if (nota == NULL) {
4344
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4345
       "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4346
       value, attr->name, elem->name);
4347
      ret = 0;
4348
        }
4349
4350
  /* Second, verify that it's among the list */
4351
  while (tree != NULL) {
4352
      if (xmlStrEqual(tree->name, value)) break;
4353
      tree = tree->next;
4354
  }
4355
  if (tree == NULL) {
4356
      xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4357
"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4358
       value, attr->name, elem->name);
4359
      ret = 0;
4360
  }
4361
    }
4362
4363
    /* Validity Constraint: Enumeration */
4364
    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4365
        xmlEnumerationPtr tree = attrDecl->tree;
4366
  while (tree != NULL) {
4367
      if (xmlStrEqual(tree->name, value)) break;
4368
      tree = tree->next;
4369
  }
4370
  if (tree == NULL) {
4371
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4372
       "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4373
       value, attr->name, elem->name);
4374
      ret = 0;
4375
  }
4376
    }
4377
4378
    /* Fixed Attribute Default */
4379
    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4380
        (!xmlStrEqual(attrDecl->defaultValue, value))) {
4381
  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4382
     "Value for attribute %s of %s must be \"%s\"\n",
4383
         attr->name, elem->name, attrDecl->defaultValue);
4384
        ret = 0;
4385
    }
4386
4387
    /* Extra check for the attribute value */
4388
    ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4389
              attrDecl->atype, value);
4390
4391
    return(ret);
4392
}
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
xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4425
    /* xmlElementPtr elemDecl; */
4426
    xmlAttributePtr attrDecl =  NULL;
4427
    int val;
4428
    int ret = 1;
4429
4430
    CHECK_DTD;
4431
    if ((elem == NULL) || (elem->name == NULL)) return(0);
4432
    if ((ns == NULL) || (ns->href == NULL)) return(0);
4433
4434
    if (prefix != NULL) {
4435
  xmlChar fn[50];
4436
  xmlChar *fullname;
4437
4438
  fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4439
  if (fullname == NULL) {
4440
      xmlVErrMemory(ctxt);
4441
      return(0);
4442
  }
4443
  if (ns->prefix != NULL) {
4444
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4445
                              ns->prefix, BAD_CAST "xmlns");
4446
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4447
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4448
            ns->prefix, BAD_CAST "xmlns");
4449
  } else {
4450
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4451
                                          BAD_CAST "xmlns", NULL);
4452
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4453
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4454
                                              BAD_CAST "xmlns", NULL);
4455
  }
4456
  if ((fullname != fn) && (fullname != elem->name))
4457
      xmlFree(fullname);
4458
    }
4459
    if (attrDecl == NULL) {
4460
  if (ns->prefix != NULL) {
4461
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4462
                              ns->prefix, BAD_CAST "xmlns");
4463
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4464
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4465
                ns->prefix, BAD_CAST "xmlns");
4466
  } else {
4467
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4468
                                          BAD_CAST "xmlns", NULL);
4469
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4470
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4471
                                              BAD_CAST "xmlns", NULL);
4472
  }
4473
    }
4474
4475
4476
    /* Validity Constraint: Attribute Value Type */
4477
    if (attrDecl == NULL) {
4478
  if (ns->prefix != NULL) {
4479
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4480
       "No declaration for attribute xmlns:%s of element %s\n",
4481
       ns->prefix, elem->name, NULL);
4482
  } else {
4483
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4484
       "No declaration for attribute xmlns of element %s\n",
4485
       elem->name, NULL, NULL);
4486
  }
4487
  return(0);
4488
    }
4489
4490
    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4491
    if (val == 0) {
4492
  if (ns->prefix != NULL) {
4493
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4494
         "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4495
       ns->prefix, elem->name, NULL);
4496
  } else {
4497
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4498
         "Syntax of value for attribute xmlns of %s is not valid\n",
4499
       elem->name, NULL, NULL);
4500
  }
4501
        ret = 0;
4502
    }
4503
4504
    /* Validity constraint: Fixed Attribute Default */
4505
    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4506
  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4507
      if (ns->prefix != NULL) {
4508
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4509
       "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4510
           ns->prefix, elem->name, attrDecl->defaultValue);
4511
      } else {
4512
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4513
       "Value for attribute xmlns of %s is different from default \"%s\"\n",
4514
           elem->name, attrDecl->defaultValue, NULL);
4515
      }
4516
      ret = 0;
4517
  }
4518
    }
4519
4520
    /* Validity Constraint: Notation Attributes */
4521
    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4522
        xmlEnumerationPtr tree = attrDecl->tree;
4523
        xmlNotationPtr nota;
4524
4525
        /* First check that the given NOTATION was declared */
4526
  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4527
  if (nota == NULL)
4528
      nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4529
4530
  if (nota == NULL) {
4531
      if (ns->prefix != NULL) {
4532
    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4533
       "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4534
           value, ns->prefix, elem->name);
4535
      } else {
4536
    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4537
       "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4538
           value, elem->name, NULL);
4539
      }
4540
      ret = 0;
4541
        }
4542
4543
  /* Second, verify that it's among the list */
4544
  while (tree != NULL) {
4545
      if (xmlStrEqual(tree->name, value)) break;
4546
      tree = tree->next;
4547
  }
4548
  if (tree == NULL) {
4549
      if (ns->prefix != NULL) {
4550
    xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4551
"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4552
           value, ns->prefix, elem->name);
4553
      } else {
4554
    xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4555
"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4556
           value, elem->name, NULL);
4557
      }
4558
      ret = 0;
4559
  }
4560
    }
4561
4562
    /* Validity Constraint: Enumeration */
4563
    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4564
        xmlEnumerationPtr tree = attrDecl->tree;
4565
  while (tree != NULL) {
4566
      if (xmlStrEqual(tree->name, value)) break;
4567
      tree = tree->next;
4568
  }
4569
  if (tree == NULL) {
4570
      if (ns->prefix != NULL) {
4571
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4572
"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4573
           value, ns->prefix, elem->name);
4574
      } else {
4575
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4576
"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4577
           value, elem->name, NULL);
4578
      }
4579
      ret = 0;
4580
  }
4581
    }
4582
4583
    /* Fixed Attribute Default */
4584
    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4585
        (!xmlStrEqual(attrDecl->defaultValue, value))) {
4586
  if (ns->prefix != NULL) {
4587
      xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4588
       "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4589
       ns->prefix, elem->name, attrDecl->defaultValue);
4590
  } else {
4591
      xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4592
       "Value for attribute xmlns of %s must be \"%s\"\n",
4593
       elem->name, attrDecl->defaultValue, NULL);
4594
  }
4595
        ret = 0;
4596
    }
4597
4598
    /* Extra check for the attribute value */
4599
    if (ns->prefix != NULL) {
4600
  ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4601
            attrDecl->atype, value);
4602
    } else {
4603
  ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4604
            attrDecl->atype, value);
4605
    }
4606
4607
    return(ret);
4608
}
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
xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
4986
    xmlNodePtr cur;
4987
    int len;
4988
4989
    if (node == NULL) return;
4990
    if (glob) strcat(buf, "(");
4991
    cur = node;
4992
    while (cur != NULL) {
4993
  len = strlen(buf);
4994
  if (size - len < 50) {
4995
      if ((size - len > 4) && (buf[len - 1] != '.'))
4996
    strcat(buf, " ...");
4997
      return;
4998
  }
4999
        switch (cur->type) {
5000
            case XML_ELEMENT_NODE: {
5001
                int qnameLen = xmlStrlen(cur->name);
5002
5003
                if ((cur->ns != NULL) && (cur->ns->prefix != NULL))
5004
                    qnameLen += xmlStrlen(cur->ns->prefix) + 1;
5005
                if (size - len < qnameLen + 10) {
5006
                    if ((size - len > 4) && (buf[len - 1] != '.'))
5007
                        strcat(buf, " ...");
5008
                    return;
5009
                }
5010
    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5011
        strcat(buf, (char *) cur->ns->prefix);
5012
        strcat(buf, ":");
5013
    }
5014
                if (cur->name != NULL)
5015
              strcat(buf, (char *) cur->name);
5016
    if (cur->next != NULL)
5017
        strcat(buf, " ");
5018
    break;
5019
            }
5020
            case XML_TEXT_NODE:
5021
    if (xmlIsBlankNode(cur))
5022
        break;
5023
                /* Falls through. */
5024
            case XML_CDATA_SECTION_NODE:
5025
            case XML_ENTITY_REF_NODE:
5026
          strcat(buf, "CDATA");
5027
    if (cur->next != NULL)
5028
        strcat(buf, " ");
5029
    break;
5030
            case XML_ATTRIBUTE_NODE:
5031
            case XML_DOCUMENT_NODE:
5032
      case XML_HTML_DOCUMENT_NODE:
5033
            case XML_DOCUMENT_TYPE_NODE:
5034
            case XML_DOCUMENT_FRAG_NODE:
5035
            case XML_NOTATION_NODE:
5036
      case XML_NAMESPACE_DECL:
5037
          strcat(buf, "???");
5038
    if (cur->next != NULL)
5039
        strcat(buf, " ");
5040
    break;
5041
            case XML_ENTITY_NODE:
5042
            case XML_PI_NODE:
5043
            case XML_DTD_NODE:
5044
            case XML_COMMENT_NODE:
5045
      case XML_ELEMENT_DECL:
5046
      case XML_ATTRIBUTE_DECL:
5047
      case XML_ENTITY_DECL:
5048
      case XML_XINCLUDE_START:
5049
      case XML_XINCLUDE_END:
5050
    break;
5051
  }
5052
  cur = cur->next;
5053
    }
5054
    if (glob) strcat(buf, ")");
5055
}
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
       xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5073
    int ret = 1;
5074
#ifndef  LIBXML_REGEXP_ENABLED
5075
    xmlNodePtr repl = NULL, last = NULL, tmp;
5076
#endif
5077
    xmlNodePtr cur;
5078
    xmlElementContentPtr cont;
5079
    const xmlChar *name;
5080
5081
    if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
5082
  return(-1);
5083
    cont = elemDecl->content;
5084
    name = elemDecl->name;
5085
5086
#ifdef LIBXML_REGEXP_ENABLED
5087
    /* Build the regexp associated to the content model */
5088
    if (elemDecl->contModel == NULL)
5089
  ret = xmlValidBuildContentModel(ctxt, elemDecl);
5090
    if (elemDecl->contModel == NULL) {
5091
  return(-1);
5092
    } else {
5093
  xmlRegExecCtxtPtr exec;
5094
5095
  if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5096
      return(-1);
5097
  }
5098
  ctxt->nodeMax = 0;
5099
  ctxt->nodeNr = 0;
5100
  ctxt->nodeTab = NULL;
5101
  exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5102
  if (exec == NULL) {
5103
            xmlVErrMemory(ctxt);
5104
            return(-1);
5105
        }
5106
        cur = child;
5107
        while (cur != NULL) {
5108
            switch (cur->type) {
5109
                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
                    if ((cur->children != NULL) &&
5115
                        (cur->children->children != NULL)) {
5116
                        if (nodeVPush(ctxt, cur) < 0) {
5117
                            ret = -1;
5118
                            goto fail;
5119
                        }
5120
                        cur = cur->children->children;
5121
                        continue;
5122
                    }
5123
                    break;
5124
                case XML_TEXT_NODE:
5125
                    if (xmlIsBlankNode(cur))
5126
                        break;
5127
                    ret = 0;
5128
                    goto fail;
5129
                case XML_CDATA_SECTION_NODE:
5130
                    /* TODO */
5131
                    ret = 0;
5132
                    goto fail;
5133
                case XML_ELEMENT_NODE:
5134
                    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5135
                        xmlChar fn[50];
5136
                        xmlChar *fullname;
5137
5138
                        fullname = xmlBuildQName(cur->name,
5139
                                                 cur->ns->prefix, fn, 50);
5140
                        if (fullname == NULL) {
5141
                            xmlVErrMemory(ctxt);
5142
                            ret = -1;
5143
                            goto fail;
5144
                        }
5145
                        ret = xmlRegExecPushString(exec, fullname, NULL);
5146
                        if ((fullname != fn) && (fullname != cur->name))
5147
                            xmlFree(fullname);
5148
                    } else {
5149
                        ret = xmlRegExecPushString(exec, cur->name, NULL);
5150
                    }
5151
                    break;
5152
                default:
5153
                    break;
5154
            }
5155
            if (ret == XML_REGEXP_OUT_OF_MEMORY)
5156
                xmlVErrMemory(ctxt);
5157
            /*
5158
             * Switch to next element
5159
             */
5160
            cur = cur->next;
5161
            while (cur == NULL) {
5162
                cur = nodeVPop(ctxt);
5163
                if (cur == NULL)
5164
                    break;
5165
                cur = cur->next;
5166
            }
5167
        }
5168
        ret = xmlRegExecPushString(exec, NULL, NULL);
5169
        if (ret == XML_REGEXP_OUT_OF_MEMORY)
5170
            xmlVErrMemory(ctxt);
5171
fail:
5172
        xmlRegFreeExecCtxt(exec);
5173
    }
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
    if ((warn) && ((ret != 1) && (ret != -3))) {
5300
  if (ctxt != NULL) {
5301
      char expr[5000];
5302
      char list[5000];
5303
5304
      expr[0] = 0;
5305
      xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5306
      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
    xmlSnprintfElements(&list[0], 5000, child, 1);
5313
5314
      if (name != NULL) {
5315
    xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5316
     "Element %s content does not follow the DTD, expecting %s, got %s\n",
5317
           name, BAD_CAST expr, BAD_CAST list);
5318
      } else {
5319
    xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5320
     "Element content does not follow the DTD, expecting %s, got %s\n",
5321
           BAD_CAST expr, BAD_CAST list, NULL);
5322
      }
5323
  } else {
5324
      if (name != NULL) {
5325
    xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5326
           "Element %s content does not follow the DTD\n",
5327
           name, NULL, NULL);
5328
      } else {
5329
    xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5330
           "Element content does not follow the DTD\n",
5331
                    NULL, NULL, NULL);
5332
      }
5333
  }
5334
  ret = 0;
5335
    }
5336
    if (ret == -3)
5337
  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
    ctxt->nodeMax = 0;
5356
    ctxt->nodeNr = 0;
5357
    if (ctxt->nodeTab != NULL) {
5358
  xmlFree(ctxt->nodeTab);
5359
  ctxt->nodeTab = NULL;
5360
    }
5361
    return(ret);
5362
5363
}
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
                           xmlNodePtr elem) {
5378
    int ret = 1;
5379
    xmlNodePtr cur, child;
5380
5381
    if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5382
        (elem->type != XML_ELEMENT_NODE))
5383
  return(0);
5384
5385
    child = elem->children;
5386
5387
    cur = child;
5388
    while (cur != NULL) {
5389
  switch (cur->type) {
5390
      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
    if ((cur->children != NULL) &&
5396
        (cur->children->children != NULL)) {
5397
        if (nodeVPush(ctxt, cur) < 0) {
5398
                        ret = 0;
5399
                        goto done;
5400
                    }
5401
        cur = cur->children->children;
5402
        continue;
5403
    }
5404
    break;
5405
      case XML_COMMENT_NODE:
5406
      case XML_PI_NODE:
5407
      case XML_TEXT_NODE:
5408
      case XML_CDATA_SECTION_NODE:
5409
    break;
5410
      default:
5411
    ret = 0;
5412
    goto done;
5413
  }
5414
  /*
5415
   * Switch to next element
5416
   */
5417
  cur = cur->next;
5418
  while (cur == NULL) {
5419
      cur = nodeVPop(ctxt);
5420
      if (cur == NULL)
5421
    break;
5422
      cur = cur->next;
5423
  }
5424
    }
5425
done:
5426
    ctxt->nodeMax = 0;
5427
    ctxt->nodeNr = 0;
5428
    if (ctxt->nodeTab != NULL) {
5429
  xmlFree(ctxt->nodeTab);
5430
  ctxt->nodeTab = NULL;
5431
    }
5432
    return(ret);
5433
}
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
                xmlElementContentPtr cont, const xmlChar *qname) {
5449
    const xmlChar *name;
5450
    int plen;
5451
    name = xmlSplitQName3(qname, &plen);
5452
5453
    if (name == NULL) {
5454
  while (cont != NULL) {
5455
      if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5456
    if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5457
        return(1);
5458
      } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5459
         (cont->c1 != NULL) &&
5460
         (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5461
    if ((cont->c1->prefix == NULL) &&
5462
        (xmlStrEqual(cont->c1->name, qname)))
5463
        return(1);
5464
      } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5465
    (cont->c1 == NULL) ||
5466
    (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5467
    xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5468
      "Internal: MIXED struct corrupted\n",
5469
      NULL);
5470
    break;
5471
      }
5472
      cont = cont->c2;
5473
  }
5474
    } else {
5475
  while (cont != NULL) {
5476
      if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5477
    if ((cont->prefix != NULL) &&
5478
        (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5479
        (xmlStrEqual(cont->name, name)))
5480
        return(1);
5481
      } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5482
         (cont->c1 != NULL) &&
5483
         (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5484
    if ((cont->c1->prefix != NULL) &&
5485
        (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5486
        (xmlStrEqual(cont->c1->name, name)))
5487
        return(1);
5488
      } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5489
    (cont->c1 == NULL) ||
5490
    (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5491
    xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5492
      "Internal: MIXED struct corrupted\n",
5493
      NULL);
5494
    break;
5495
      }
5496
      cont = cont->c2;
5497
  }
5498
    }
5499
    return(0);
5500
}
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
              xmlNodePtr elem, int *extsubset) {
5518
    xmlElementPtr elemDecl = NULL;
5519
    const xmlChar *prefix = NULL;
5520
5521
    if ((ctxt == NULL) || (doc == NULL) ||
5522
        (elem == NULL) || (elem->name == NULL))
5523
        return(NULL);
5524
    if (extsubset != NULL)
5525
  *extsubset = 0;
5526
5527
    /*
5528
     * Fetch the declaration for the qualified name
5529
     */
5530
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5531
  prefix = elem->ns->prefix;
5532
5533
    if (prefix != NULL) {
5534
  elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5535
                             elem->name, prefix);
5536
  if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5537
      elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5538
                                 elem->name, prefix);
5539
      if ((elemDecl != NULL) && (extsubset != NULL))
5540
    *extsubset = 1;
5541
  }
5542
    }
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
    if (elemDecl == NULL) {
5550
  elemDecl = xmlGetDtdQElementDesc(doc->intSubset, elem->name, NULL);
5551
  if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5552
      elemDecl = xmlGetDtdQElementDesc(doc->extSubset, elem->name, NULL);
5553
      if ((elemDecl != NULL) && (extsubset != NULL))
5554
    *extsubset = 1;
5555
  }
5556
    }
5557
    if (elemDecl == NULL) {
5558
  xmlErrValidNode(ctxt, elem,
5559
      XML_DTD_UNKNOWN_ELEM,
5560
         "No declaration for element %s\n",
5561
         elem->name, NULL, NULL);
5562
    }
5563
    return(elemDecl);
5564
}
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
                       xmlNodePtr elem, const xmlChar *qname) {
5583
    int ret = 1;
5584
    xmlElementPtr eDecl;
5585
    int extsubset = 0;
5586
5587
    if (ctxt == NULL)
5588
        return(0);
5589
5590
    if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5591
  xmlValidStatePtr state = ctxt->vstate;
5592
  xmlElementPtr elemDecl;
5593
5594
  /*
5595
   * Check the new element against the content model of the new elem.
5596
   */
5597
  if (state->elemDecl != NULL) {
5598
      elemDecl = state->elemDecl;
5599
5600
      switch(elemDecl->etype) {
5601
    case XML_ELEMENT_TYPE_UNDEFINED:
5602
        ret = 0;
5603
        break;
5604
    case XML_ELEMENT_TYPE_EMPTY:
5605
        xmlErrValidNode(ctxt, state->node,
5606
            XML_DTD_NOT_EMPTY,
5607
         "Element %s was declared EMPTY this one has content\n",
5608
         state->node->name, NULL, NULL);
5609
        ret = 0;
5610
        break;
5611
    case XML_ELEMENT_TYPE_ANY:
5612
        /* I don't think anything is required then */
5613
        break;
5614
    case XML_ELEMENT_TYPE_MIXED:
5615
        /* simple case of declared as #PCDATA */
5616
        if ((elemDecl->content != NULL) &&
5617
      (elemDecl->content->type ==
5618
       XML_ELEMENT_CONTENT_PCDATA)) {
5619
      xmlErrValidNode(ctxt, state->node,
5620
          XML_DTD_NOT_PCDATA,
5621
         "Element %s was declared #PCDATA but contains non text nodes\n",
5622
        state->node->name, NULL, NULL);
5623
      ret = 0;
5624
        } else {
5625
      ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5626
                            qname);
5627
      if (ret != 1) {
5628
          xmlErrValidNode(ctxt, state->node,
5629
              XML_DTD_INVALID_CHILD,
5630
         "Element %s is not declared in %s list of possible children\n",
5631
            qname, state->node->name, NULL);
5632
      }
5633
        }
5634
        break;
5635
    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
        if (state->exec != NULL) {
5643
      ret = xmlRegExecPushString(state->exec, qname, NULL);
5644
                        if (ret == XML_REGEXP_OUT_OF_MEMORY) {
5645
                            xmlVErrMemory(ctxt);
5646
                            return(0);
5647
                        }
5648
      if (ret < 0) {
5649
          xmlErrValidNode(ctxt, state->node,
5650
              XML_DTD_CONTENT_MODEL,
5651
         "Element %s content does not follow the DTD, Misplaced %s\n",
5652
           state->node->name, qname, NULL);
5653
          ret = 0;
5654
      } else {
5655
          ret = 1;
5656
      }
5657
        }
5658
        break;
5659
      }
5660
  }
5661
    }
5662
    eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5663
    vstateVPush(ctxt, eDecl, elem);
5664
    return(ret);
5665
}
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
xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5681
    int ret = 1;
5682
5683
    if (ctxt == NULL)
5684
        return(0);
5685
    if (len <= 0)
5686
  return(ret);
5687
    if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5688
  xmlValidStatePtr state = ctxt->vstate;
5689
  xmlElementPtr elemDecl;
5690
5691
  /*
5692
   * Check the new element against the content model of the new elem.
5693
   */
5694
  if (state->elemDecl != NULL) {
5695
      elemDecl = state->elemDecl;
5696
5697
      switch(elemDecl->etype) {
5698
    case XML_ELEMENT_TYPE_UNDEFINED:
5699
        ret = 0;
5700
        break;
5701
    case XML_ELEMENT_TYPE_EMPTY:
5702
        xmlErrValidNode(ctxt, state->node,
5703
            XML_DTD_NOT_EMPTY,
5704
         "Element %s was declared EMPTY this one has content\n",
5705
         state->node->name, NULL, NULL);
5706
        ret = 0;
5707
        break;
5708
    case XML_ELEMENT_TYPE_ANY:
5709
        break;
5710
    case XML_ELEMENT_TYPE_MIXED:
5711
        break;
5712
    case XML_ELEMENT_TYPE_ELEMENT: {
5713
                    int i;
5714
5715
                    for (i = 0;i < len;i++) {
5716
                        if (!IS_BLANK_CH(data[i])) {
5717
                            xmlErrValidNode(ctxt, state->node,
5718
                                            XML_DTD_CONTENT_MODEL,
5719
       "Element %s content does not follow the DTD, Text not allowed\n",
5720
                                   state->node->name, NULL, NULL);
5721
                            ret = 0;
5722
                            goto done;
5723
                        }
5724
                    }
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
                    break;
5732
                }
5733
      }
5734
  }
5735
    }
5736
done:
5737
    return(ret);
5738
}
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
          const xmlChar *qname ATTRIBUTE_UNUSED) {
5757
    int ret = 1;
5758
5759
    if (ctxt == NULL)
5760
        return(0);
5761
5762
    if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5763
  xmlValidStatePtr state = ctxt->vstate;
5764
  xmlElementPtr elemDecl;
5765
5766
  /*
5767
   * Check the new element against the content model of the new elem.
5768
   */
5769
  if (state->elemDecl != NULL) {
5770
      elemDecl = state->elemDecl;
5771
5772
      if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5773
    if (state->exec != NULL) {
5774
        ret = xmlRegExecPushString(state->exec, NULL, NULL);
5775
        if (ret <= 0) {
5776
                        if (ret == XML_REGEXP_OUT_OF_MEMORY)
5777
                            xmlVErrMemory(ctxt);
5778
                        else
5779
          xmlErrValidNode(ctxt, state->node,
5780
                          XML_DTD_CONTENT_MODEL,
5781
     "Element %s content does not follow the DTD, Expecting more children\n",
5782
             state->node->name, NULL,NULL);
5783
      ret = 0;
5784
        } else {
5785
      /*
5786
       * previous validation errors should not generate
5787
       * a new one here
5788
       */
5789
      ret = 1;
5790
        }
5791
    }
5792
      }
5793
  }
5794
  vstateVPop(ctxt);
5795
    }
5796
    return(ret);
5797
}
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
                      xmlNodePtr elem) {
5823
    xmlElementPtr elemDecl = NULL;
5824
    xmlElementContentPtr cont;
5825
    xmlAttributePtr attr;
5826
    xmlNodePtr child;
5827
    int ret = 1, tmp;
5828
    const xmlChar *name;
5829
    int extsubset = 0;
5830
5831
    CHECK_DTD;
5832
5833
    if (elem == NULL) return(0);
5834
    switch (elem->type) {
5835
        case XML_TEXT_NODE:
5836
        case XML_CDATA_SECTION_NODE:
5837
        case XML_ENTITY_REF_NODE:
5838
        case XML_PI_NODE:
5839
        case XML_COMMENT_NODE:
5840
        case XML_XINCLUDE_START:
5841
        case XML_XINCLUDE_END:
5842
      return(1);
5843
        case XML_ELEMENT_NODE:
5844
      break;
5845
  default:
5846
      xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5847
       "unexpected element type\n", NULL, NULL ,NULL);
5848
      return(0);
5849
    }
5850
5851
    /*
5852
     * Fetch the declaration
5853
     */
5854
    elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5855
    if (elemDecl == NULL)
5856
  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
    if (ctxt->vstateNr == 0) {
5863
    /* Check that the element content matches the definition */
5864
    switch (elemDecl->etype) {
5865
        case XML_ELEMENT_TYPE_UNDEFINED:
5866
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5867
                      "No declaration for element %s\n",
5868
       elem->name, NULL, NULL);
5869
      return(0);
5870
        case XML_ELEMENT_TYPE_EMPTY:
5871
      if (elem->children != NULL) {
5872
    xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
5873
         "Element %s was declared EMPTY this one has content\n",
5874
                 elem->name, NULL, NULL);
5875
    ret = 0;
5876
      }
5877
      break;
5878
        case XML_ELEMENT_TYPE_ANY:
5879
      /* I don't think anything is required then */
5880
      break;
5881
        case XML_ELEMENT_TYPE_MIXED:
5882
5883
      /* simple case of declared as #PCDATA */
5884
      if ((elemDecl->content != NULL) &&
5885
    (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5886
    ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5887
    if (!ret) {
5888
        xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
5889
         "Element %s was declared #PCDATA but contains non text nodes\n",
5890
         elem->name, NULL, NULL);
5891
    }
5892
    break;
5893
      }
5894
      child = elem->children;
5895
      /* Hum, this start to get messy */
5896
      while (child != NULL) {
5897
          if (child->type == XML_ELEMENT_NODE) {
5898
        name = child->name;
5899
        if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
5900
      xmlChar fn[50];
5901
      xmlChar *fullname;
5902
5903
      fullname = xmlBuildQName(child->name, child->ns->prefix,
5904
                         fn, 50);
5905
      if (fullname == NULL) {
5906
                            xmlVErrMemory(ctxt);
5907
          return(0);
5908
                        }
5909
      cont = elemDecl->content;
5910
      while (cont != NULL) {
5911
          if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5912
        if (xmlStrEqual(cont->name, fullname))
5913
            break;
5914
          } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5915
             (cont->c1 != NULL) &&
5916
             (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5917
        if (xmlStrEqual(cont->c1->name, fullname))
5918
            break;
5919
          } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5920
        (cont->c1 == NULL) ||
5921
        (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5922
        xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5923
          "Internal: MIXED struct corrupted\n",
5924
          NULL);
5925
        break;
5926
          }
5927
          cont = cont->c2;
5928
      }
5929
      if ((fullname != fn) && (fullname != child->name))
5930
          xmlFree(fullname);
5931
      if (cont != NULL)
5932
          goto child_ok;
5933
        }
5934
        cont = elemDecl->content;
5935
        while (cont != NULL) {
5936
            if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5937
          if (xmlStrEqual(cont->name, name)) break;
5938
      } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5939
         (cont->c1 != NULL) &&
5940
         (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5941
          if (xmlStrEqual(cont->c1->name, name)) break;
5942
      } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5943
          (cont->c1 == NULL) ||
5944
          (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
5945
          xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5946
            "Internal: MIXED struct corrupted\n",
5947
            NULL);
5948
          break;
5949
      }
5950
      cont = cont->c2;
5951
        }
5952
        if (cont == NULL) {
5953
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
5954
         "Element %s is not declared in %s list of possible children\n",
5955
             name, elem->name, NULL);
5956
      ret = 0;
5957
        }
5958
    }
5959
child_ok:
5960
          child = child->next;
5961
      }
5962
      break;
5963
        case XML_ELEMENT_TYPE_ELEMENT:
5964
      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
    child = elem->children;
5971
    while (child != NULL) {
5972
        if ((child->type == XML_TEXT_NODE) &&
5973
                        (child->content != NULL)) {
5974
      const xmlChar *content = child->content;
5975
5976
      while (IS_BLANK_CH(*content))
5977
          content++;
5978
      if (*content == 0) {
5979
          xmlErrValidNode(ctxt, elem,
5980
                          XML_DTD_STANDALONE_WHITE_SPACE,
5981
"standalone: %s declared in the external subset contains white spaces nodes\n",
5982
           elem->name, NULL, NULL);
5983
          ret = 0;
5984
          break;
5985
      }
5986
        }
5987
        child =child->next;
5988
    }
5989
      }
5990
      child = elem->children;
5991
      cont = elemDecl->content;
5992
      tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
5993
      if (tmp <= 0)
5994
    ret = 0;
5995
      break;
5996
    }
5997
    } /* not continuous */
5998
5999
    /* [ VC: Required Attribute ] */
6000
    attr = elemDecl->attributes;
6001
    while (attr != NULL) {
6002
  if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6003
      int qualified = -1;
6004
6005
      if ((attr->prefix == NULL) &&
6006
    (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6007
    xmlNsPtr ns;
6008
6009
    ns = elem->nsDef;
6010
    while (ns != NULL) {
6011
        if (ns->prefix == NULL)
6012
      goto found;
6013
        ns = ns->next;
6014
    }
6015
      } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6016
    xmlNsPtr ns;
6017
6018
    ns = elem->nsDef;
6019
    while (ns != NULL) {
6020
        if (xmlStrEqual(attr->name, ns->prefix))
6021
      goto found;
6022
        ns = ns->next;
6023
    }
6024
      } else {
6025
    xmlAttrPtr attrib;
6026
6027
    attrib = elem->properties;
6028
    while (attrib != NULL) {
6029
        if (xmlStrEqual(attrib->name, attr->name)) {
6030
      if (attr->prefix != NULL) {
6031
          xmlNsPtr nameSpace = attrib->ns;
6032
6033
          if (nameSpace == NULL)
6034
        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
          if (nameSpace == NULL) {
6041
        if (qualified < 0)
6042
            qualified = 0;
6043
          } else if (!xmlStrEqual(nameSpace->prefix,
6044
                attr->prefix)) {
6045
        if (qualified < 1)
6046
            qualified = 1;
6047
          } else
6048
        goto found;
6049
      } 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
          goto found;
6057
      }
6058
        }
6059
        attrib = attrib->next;
6060
    }
6061
      }
6062
      if (qualified == -1) {
6063
    if (attr->prefix == NULL) {
6064
        xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6065
           "Element %s does not carry attribute %s\n",
6066
         elem->name, attr->name, NULL);
6067
        ret = 0;
6068
          } else {
6069
        xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6070
           "Element %s does not carry attribute %s:%s\n",
6071
         elem->name, attr->prefix,attr->name);
6072
        ret = 0;
6073
    }
6074
      } else if (qualified == 0) {
6075
    xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6076
       "Element %s required attribute %s:%s has no prefix\n",
6077
           elem->name, attr->prefix, attr->name);
6078
      } else if (qualified == 1) {
6079
    xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6080
       "Element %s required attribute %s:%s has different prefix\n",
6081
           elem->name, attr->prefix, attr->name);
6082
      }
6083
  } 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
      if ((attr->prefix == NULL) &&
6090
    (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6091
    xmlNsPtr ns;
6092
6093
    ns = elem->nsDef;
6094
    while (ns != NULL) {
6095
        if (ns->prefix == NULL) {
6096
      if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6097
          xmlErrValidNode(ctxt, elem,
6098
                 XML_DTD_ELEM_DEFAULT_NAMESPACE,
6099
   "Element %s namespace name for default namespace does not match the DTD\n",
6100
           elem->name, NULL, NULL);
6101
          ret = 0;
6102
      }
6103
      goto found;
6104
        }
6105
        ns = ns->next;
6106
    }
6107
      } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6108
    xmlNsPtr ns;
6109
6110
    ns = elem->nsDef;
6111
    while (ns != NULL) {
6112
        if (xmlStrEqual(attr->name, ns->prefix)) {
6113
      if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6114
          xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6115
       "Element %s namespace name for %s does not match the DTD\n",
6116
           elem->name, ns->prefix, NULL);
6117
          ret = 0;
6118
      }
6119
      goto found;
6120
        }
6121
        ns = ns->next;
6122
    }
6123
      }
6124
  }
6125
found:
6126
        attr = attr->nexth;
6127
    }
6128
    return(ret);
6129
}
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
xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6149
    xmlNodePtr root;
6150
    int ret;
6151
6152
    if (doc == NULL) return(0);
6153
6154
    root = xmlDocGetRootElement(doc);
6155
    if ((root == NULL) || (root->name == NULL)) {
6156
  xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6157
              "no root element\n", NULL);
6158
        return(0);
6159
    }
6160
6161
    /*
6162
     * When doing post validation against a separate DTD, those may
6163
     * no internal subset has been generated
6164
     */
6165
    if ((doc->intSubset != NULL) &&
6166
  (doc->intSubset->name != NULL)) {
6167
  /*
6168
   * Check first the document root against the NQName
6169
   */
6170
  if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6171
      if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6172
    xmlChar fn[50];
6173
    xmlChar *fullname;
6174
6175
    fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6176
    if (fullname == NULL) {
6177
        xmlVErrMemory(ctxt);
6178
        return(0);
6179
    }
6180
    ret = xmlStrEqual(doc->intSubset->name, fullname);
6181
    if ((fullname != fn) && (fullname != root->name))
6182
        xmlFree(fullname);
6183
    if (ret == 1)
6184
        goto name_ok;
6185
      }
6186
      if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6187
    (xmlStrEqual(root->name, BAD_CAST "html")))
6188
    goto name_ok;
6189
      xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6190
       "root and DTD name do not match '%s' and '%s'\n",
6191
       root->name, doc->intSubset->name, NULL);
6192
      return(0);
6193
  }
6194
    }
6195
name_ok:
6196
    return(1);
6197
}
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
xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) {
6213
    xmlNodePtr elem;
6214
    xmlAttrPtr attr;
6215
    xmlNsPtr ns;
6216
    const xmlChar *value;
6217
    int ret = 1;
6218
6219
    if (root == NULL) return(0);
6220
6221
    CHECK_DTD;
6222
6223
    elem = root;
6224
    while (1) {
6225
        ret &= xmlValidateOneElement(ctxt, doc, elem);
6226
6227
        if (elem->type == XML_ELEMENT_NODE) {
6228
            attr = elem->properties;
6229
            while (attr != NULL) {
6230
                if (attr->children == NULL)
6231
                    value = xmlStrdup(BAD_CAST "");
6232
                else
6233
                    value = xmlNodeListGetString(doc, attr->children, 0);
6234
                if (value == NULL) {
6235
                    xmlVErrMemory(ctxt);
6236
                    ret = 0;
6237
                } else {
6238
                    ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6239
                    xmlFree((char *)value);
6240
                }
6241
                attr= attr->next;
6242
            }
6243
6244
            ns = elem->nsDef;
6245
            while (ns != NULL) {
6246
                if (elem->ns == NULL)
6247
                    ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6248
                                                   ns, ns->href);
6249
                else
6250
                    ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6251
                                                   elem->ns->prefix, ns,
6252
                                                   ns->href);
6253
                ns = ns->next;
6254
            }
6255
6256
            if (elem->children != NULL) {
6257
                elem = elem->children;
6258
                continue;
6259
            }
6260
        }
6261
6262
        while (1) {
6263
            if (elem == root)
6264
                goto done;
6265
            if (elem->next != NULL)
6266
                break;
6267
            elem = elem->parent;
6268
        }
6269
        elem = elem->next;
6270
    }
6271
6272
done:
6273
    return(ret);
6274
}
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
                     const xmlChar *name) {
6286
    xmlAttrPtr id;
6287
    xmlAttrPtr attr;
6288
6289
    if (ref == NULL)
6290
  return;
6291
    if ((ref->attr == NULL) && (ref->name == NULL))
6292
  return;
6293
    attr = ref->attr;
6294
    if (attr == NULL) {
6295
  xmlChar *dup, *str = NULL, *cur, save;
6296
6297
  dup = xmlStrdup(name);
6298
  if (dup == NULL) {
6299
            xmlVErrMemory(ctxt);
6300
      return;
6301
  }
6302
  cur = dup;
6303
  while (*cur != 0) {
6304
      str = cur;
6305
      while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6306
      save = *cur;
6307
      *cur = 0;
6308
      id = xmlGetID(ctxt->doc, str);
6309
      if (id == NULL) {
6310
    xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6311
     "attribute %s line %d references an unknown ID \"%s\"\n",
6312
           ref->name, ref->lineno, str);
6313
    ctxt->valid = 0;
6314
      }
6315
      if (save == 0)
6316
    break;
6317
      *cur = save;
6318
      while (IS_BLANK_CH(*cur)) cur++;
6319
  }
6320
  xmlFree(dup);
6321
    } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6322
  id = xmlGetID(ctxt->doc, name);
6323
  if (id == NULL) {
6324
      xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6325
     "IDREF attribute %s references an unknown ID \"%s\"\n",
6326
       attr->name, name, NULL);
6327
      ctxt->valid = 0;
6328
  }
6329
    } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6330
  xmlChar *dup, *str = NULL, *cur, save;
6331
6332
  dup = xmlStrdup(name);
6333
  if (dup == NULL) {
6334
      xmlVErrMemory(ctxt);
6335
      ctxt->valid = 0;
6336
      return;
6337
  }
6338
  cur = dup;
6339
  while (*cur != 0) {
6340
      str = cur;
6341
      while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6342
      save = *cur;
6343
      *cur = 0;
6344
      id = xmlGetID(ctxt->doc, str);
6345
      if (id == NULL) {
6346
    xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6347
     "IDREFS attribute %s references an unknown ID \"%s\"\n",
6348
           attr->name, str, NULL);
6349
    ctxt->valid = 0;
6350
      }
6351
      if (save == 0)
6352
    break;
6353
      *cur = save;
6354
      while (IS_BLANK_CH(*cur)) cur++;
6355
  }
6356
  xmlFree(dup);
6357
    }
6358
}
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
{
6370
  xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6371
  xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6372
  return 1;
6373
}
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
xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) {
6384
    xmlListPtr ref_list = (xmlListPtr) payload;
6385
    xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6386
    xmlValidateMemo memo;
6387
6388
    if (ref_list == NULL)
6389
  return;
6390
    memo.ctxt = ctxt;
6391
    memo.name = name;
6392
6393
    xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6394
6395
}
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
xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6416
    xmlRefTablePtr table;
6417
    xmlParserCtxtPtr pctxt = NULL;
6418
    xmlParserInputPtr oldInput = NULL;
6419
6420
    if (ctxt == NULL)
6421
        return(0);
6422
    if (doc == NULL) {
6423
        xmlErrValid(ctxt, XML_DTD_NO_DOC,
6424
    "xmlValidateDocumentFinal: doc == NULL\n", NULL);
6425
  return(0);
6426
    }
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
    if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
6442
        pctxt = ctxt->userData;
6443
        oldInput = pctxt->input;
6444
        pctxt->input = NULL;
6445
    }
6446
6447
    table = (xmlRefTablePtr) doc->refs;
6448
    ctxt->doc = doc;
6449
    ctxt->valid = 1;
6450
    xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
6451
6452
    if (ctxt->flags & XML_VCTXT_USE_PCTXT)
6453
        pctxt->input = oldInput;
6454
6455
    return(ctxt->valid);
6456
}
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
xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6476
    int ret;
6477
    xmlDtdPtr oldExt, oldInt;
6478
    xmlNodePtr root;
6479
6480
    if (dtd == NULL)
6481
        return(0);
6482
    if (doc == NULL)
6483
        return(0);
6484
6485
    oldExt = doc->extSubset;
6486
    oldInt = doc->intSubset;
6487
    doc->extSubset = dtd;
6488
    doc->intSubset = NULL;
6489
    if (doc->ids != NULL) {
6490
        xmlFreeIDTable(doc->ids);
6491
        doc->ids = NULL;
6492
    }
6493
    if (doc->refs != NULL) {
6494
        xmlFreeRefTable(doc->refs);
6495
        doc->refs = NULL;
6496
    }
6497
6498
    ret = xmlValidateRoot(ctxt, doc);
6499
    if (ret != 0) {
6500
        root = xmlDocGetRootElement(doc);
6501
        ret = xmlValidateElement(ctxt, doc, root);
6502
        ret &= xmlValidateDocumentFinal(ctxt, doc);
6503
    }
6504
6505
    doc->extSubset = oldExt;
6506
    doc->intSubset = oldInt;
6507
    if (doc->ids != NULL) {
6508
        xmlFreeIDTable(doc->ids);
6509
        doc->ids = NULL;
6510
    }
6511
    if (doc->refs != NULL) {
6512
        xmlFreeRefTable(doc->refs);
6513
        doc->refs = NULL;
6514
    }
6515
6516
    return(ret);
6517
}
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
xmlCtxtValidateDtd(xmlParserCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6535
    if ((ctxt == NULL) || (ctxt->html))
6536
        return(0);
6537
6538
    xmlCtxtReset(ctxt);
6539
6540
    return(xmlValidateDtd(&ctxt->vctxt, doc, dtd));
6541
}
6542
6543
static void
6544
xmlValidateNotationCallback(void *payload, void *data,
6545
                      const xmlChar *name ATTRIBUTE_UNUSED) {
6546
    xmlEntityPtr cur = (xmlEntityPtr) payload;
6547
    xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6548
    if (cur == NULL)
6549
  return;
6550
    if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6551
  xmlChar *notation = cur->content;
6552
6553
  if (notation != NULL) {
6554
      int ret;
6555
6556
      ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6557
      if (ret != 1) {
6558
    ctxt->valid = 0;
6559
      }
6560
  }
6561
    }
6562
}
6563
6564
static void
6565
xmlValidateAttributeCallback(void *payload, void *data,
6566
                       const xmlChar *name ATTRIBUTE_UNUSED) {
6567
    xmlAttributePtr cur = (xmlAttributePtr) payload;
6568
    xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6569
    int ret;
6570
    xmlDocPtr doc;
6571
    xmlElementPtr elem = NULL;
6572
6573
    if (cur == NULL)
6574
  return;
6575
    switch (cur->atype) {
6576
  case XML_ATTRIBUTE_CDATA:
6577
  case XML_ATTRIBUTE_ID:
6578
  case XML_ATTRIBUTE_IDREF  :
6579
  case XML_ATTRIBUTE_IDREFS:
6580
  case XML_ATTRIBUTE_NMTOKEN:
6581
  case XML_ATTRIBUTE_NMTOKENS:
6582
  case XML_ATTRIBUTE_ENUMERATION:
6583
      break;
6584
  case XML_ATTRIBUTE_ENTITY:
6585
  case XML_ATTRIBUTE_ENTITIES:
6586
  case XML_ATTRIBUTE_NOTATION:
6587
      if (cur->defaultValue != NULL) {
6588
6589
    ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6590
                               cur->atype, cur->defaultValue);
6591
    if ((ret == 0) && (ctxt->valid == 1))
6592
        ctxt->valid = 0;
6593
      }
6594
      if (cur->tree != NULL) {
6595
    xmlEnumerationPtr tree = cur->tree;
6596
    while (tree != NULL) {
6597
        ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6598
            cur->name, cur->atype, tree->name);
6599
        if ((ret == 0) && (ctxt->valid == 1))
6600
      ctxt->valid = 0;
6601
        tree = tree->next;
6602
    }
6603
      }
6604
    }
6605
    if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6606
        const xmlChar *elemLocalName;
6607
        xmlChar *elemPrefix;
6608
6609
  doc = cur->doc;
6610
  if (cur->elem == NULL) {
6611
      xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
6612
       "xmlValidateAttributeCallback(%s): internal error\n",
6613
       (const char *) cur->name);
6614
      return;
6615
  }
6616
6617
        elemLocalName = xmlSplitQName4(cur->elem, &elemPrefix);
6618
        if (elemLocalName == NULL) {
6619
            xmlVErrMemory(ctxt);
6620
            return;
6621
        }
6622
6623
  if ((doc != NULL) && (doc->intSubset != NULL))
6624
      elem = xmlHashLookup2(doc->intSubset->elements,
6625
                                  elemLocalName, elemPrefix);
6626
  if ((elem == NULL) && (doc != NULL) && (doc->extSubset != NULL))
6627
      elem = xmlHashLookup2(doc->extSubset->elements,
6628
                                  elemLocalName, elemPrefix);
6629
  if ((elem == NULL) && (cur->parent != NULL) &&
6630
      (cur->parent->type == XML_DTD_NODE))
6631
      elem = xmlHashLookup2(((xmlDtdPtr) cur->parent)->elements,
6632
                                  elemLocalName, elemPrefix);
6633
6634
        xmlFree(elemPrefix);
6635
6636
  if (elem == NULL) {
6637
      xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
6638
       "attribute %s: could not find decl for element %s\n",
6639
       cur->name, cur->elem, NULL);
6640
      return;
6641
  }
6642
  if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6643
      xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6644
       "NOTATION attribute %s declared for EMPTY element %s\n",
6645
       cur->name, cur->elem, NULL);
6646
      ctxt->valid = 0;
6647
  }
6648
    }
6649
}
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
xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6672
    xmlDtdPtr dtd;
6673
    xmlAttributeTablePtr table;
6674
    xmlEntitiesTablePtr entities;
6675
6676
    if ((doc == NULL) || (ctxt == NULL)) return(0);
6677
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6678
  return(0);
6679
    ctxt->doc = doc;
6680
    ctxt->valid = 1;
6681
    dtd = doc->intSubset;
6682
    if ((dtd != NULL) && (dtd->attributes != NULL)) {
6683
  table = (xmlAttributeTablePtr) dtd->attributes;
6684
  xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6685
    }
6686
    if ((dtd != NULL) && (dtd->entities != NULL)) {
6687
  entities = (xmlEntitiesTablePtr) dtd->entities;
6688
  xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6689
    }
6690
    dtd = doc->extSubset;
6691
    if ((dtd != NULL) && (dtd->attributes != NULL)) {
6692
  table = (xmlAttributeTablePtr) dtd->attributes;
6693
  xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6694
    }
6695
    if ((dtd != NULL) && (dtd->entities != NULL)) {
6696
  entities = (xmlEntitiesTablePtr) dtd->entities;
6697
  xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6698
    }
6699
    return(ctxt->valid);
6700
}
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
                            xmlDocPtr doc) {
6715
    int ret;
6716
    xmlNodePtr root;
6717
6718
    if (doc == NULL)
6719
        return(0);
6720
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6721
        xmlErrValid(vctxt, XML_DTD_NO_DTD,
6722
              "no DTD found!\n", NULL);
6723
  return(0);
6724
    }
6725
6726
    if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6727
  (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6728
  xmlChar *sysID = NULL;
6729
6730
  if (doc->intSubset->SystemID != NULL) {
6731
            int res;
6732
6733
            res = xmlBuildURISafe(doc->intSubset->SystemID, doc->URL, &sysID);
6734
            if (res < 0) {
6735
                xmlVErrMemory(vctxt);
6736
                return 0;
6737
            } else if (res != 0) {
6738
                xmlErrValid(vctxt, XML_DTD_LOAD_ERROR,
6739
      "Could not build URI for external subset \"%s\"\n",
6740
      (const char *) doc->intSubset->SystemID);
6741
    return 0;
6742
      }
6743
  }
6744
6745
        if (ctxt != NULL) {
6746
            xmlParserInputPtr input;
6747
6748
            input = xmlLoadResource(ctxt, (const char *) sysID,
6749
                    (const char *) doc->intSubset->ExternalID,
6750
                    XML_RESOURCE_DTD);
6751
            if (input == NULL) {
6752
                xmlFree(sysID);
6753
                return 0;
6754
            }
6755
6756
            doc->extSubset = xmlCtxtParseDtd(ctxt, input,
6757
                                             doc->intSubset->ExternalID,
6758
                                             sysID);
6759
        } else {
6760
            doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID, sysID);
6761
        }
6762
6763
  if (sysID != NULL)
6764
      xmlFree(sysID);
6765
        if (doc->extSubset == NULL) {
6766
      if (doc->intSubset->SystemID != NULL) {
6767
    xmlErrValid(vctxt, XML_DTD_LOAD_ERROR,
6768
           "Could not load the external subset \"%s\"\n",
6769
           (const char *) doc->intSubset->SystemID);
6770
      } else {
6771
    xmlErrValid(vctxt, XML_DTD_LOAD_ERROR,
6772
           "Could not load the external subset \"%s\"\n",
6773
           (const char *) doc->intSubset->ExternalID);
6774
      }
6775
      return(0);
6776
  }
6777
    }
6778
6779
    if (doc->ids != NULL) {
6780
          xmlFreeIDTable(doc->ids);
6781
          doc->ids = NULL;
6782
    }
6783
    if (doc->refs != NULL) {
6784
          xmlFreeRefTable(doc->refs);
6785
          doc->refs = NULL;
6786
    }
6787
    ret = xmlValidateDtdFinal(vctxt, doc);
6788
    if (!xmlValidateRoot(vctxt, doc)) return(0);
6789
6790
    root = xmlDocGetRootElement(doc);
6791
    ret &= xmlValidateElement(vctxt, doc, root);
6792
    ret &= xmlValidateDocumentFinal(vctxt, doc);
6793
    return(ret);
6794
}
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
xmlValidateDocument(xmlValidCtxtPtr vctxt, xmlDocPtr doc) {
6814
    return(xmlValidateDocumentInternal(NULL, vctxt, doc));
6815
}
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
xmlCtxtValidateDocument(xmlParserCtxtPtr ctxt, xmlDocPtr doc) {
6835
    if ((ctxt == NULL) || (ctxt->html))
6836
        return(0);
6837
6838
    xmlCtxtReset(ctxt);
6839
6840
    return(xmlValidateDocumentInternal(ctxt, &ctxt->vctxt, doc));
6841
}
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
                             int *len, int max) {
6865
    int i;
6866
6867
    if ((ctree == NULL) || (names == NULL) || (len == NULL))
6868
        return(-1);
6869
    if (*len >= max) return(*len);
6870
6871
    switch (ctree->type) {
6872
  case XML_ELEMENT_CONTENT_PCDATA:
6873
      for (i = 0; i < *len;i++)
6874
    if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6875
      names[(*len)++] = BAD_CAST "#PCDATA";
6876
      break;
6877
  case XML_ELEMENT_CONTENT_ELEMENT:
6878
      for (i = 0; i < *len;i++)
6879
    if (xmlStrEqual(ctree->name, names[i])) return(*len);
6880
      names[(*len)++] = ctree->name;
6881
      break;
6882
  case XML_ELEMENT_CONTENT_SEQ:
6883
      xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6884
      xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6885
      break;
6886
  case XML_ELEMENT_CONTENT_OR:
6887
      xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6888
      xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6889
      break;
6890
   }
6891
6892
   return(*len);
6893
}
6894
6895
/*
6896
 * Dummy function to suppress messages while we try out valid elements
6897
 */
6898
static void xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6899
                                const char *msg ATTRIBUTE_UNUSED, ...) {
6900
}
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
                         int max) {
6930
    xmlValidCtxt vctxt;
6931
    int nb_valid_elements = 0;
6932
    const xmlChar *elements[256]={0};
6933
    int nb_elements = 0, i;
6934
    const xmlChar *name;
6935
6936
    xmlNode *ref_node;
6937
    xmlNode *parent;
6938
    xmlNode *test_node;
6939
6940
    xmlNode *prev_next;
6941
    xmlNode *next_prev;
6942
    xmlNode *parent_childs;
6943
    xmlNode *parent_last;
6944
6945
    xmlElement *element_desc;
6946
6947
    if (prev == NULL && next == NULL)
6948
        return(-1);
6949
6950
    if (names == NULL) return(-1);
6951
    if (max <= 0) return(-1);
6952
6953
    memset(&vctxt, 0, sizeof (xmlValidCtxt));
6954
    vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6955
6956
    nb_valid_elements = 0;
6957
    ref_node = prev ? prev : next;
6958
    parent = ref_node->parent;
6959
6960
    /*
6961
     * Retrieves the parent element declaration
6962
     */
6963
    element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6964
                                         parent->name);
6965
    if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6966
        element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6967
                                             parent->name);
6968
    if (element_desc == NULL) return(-1);
6969
6970
    /*
6971
     * Do a backup of the current tree structure
6972
     */
6973
    prev_next = prev ? prev->next : NULL;
6974
    next_prev = next ? next->prev : NULL;
6975
    parent_childs = parent->children;
6976
    parent_last = parent->last;
6977
6978
    /*
6979
     * Creates a dummy node and insert it into the tree
6980
     */
6981
    test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
6982
    if (test_node == NULL)
6983
        return(-1);
6984
6985
    test_node->parent = parent;
6986
    test_node->prev = prev;
6987
    test_node->next = next;
6988
    name = test_node->name;
6989
6990
    if (prev) prev->next = test_node;
6991
    else parent->children = test_node;
6992
6993
    if (next) next->prev = test_node;
6994
    else parent->last = test_node;
6995
6996
    /*
6997
     * Insert each potential child node and check if the parent is
6998
     * still valid
6999
     */
7000
    nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7001
           elements, &nb_elements, 256);
7002
7003
    for (i = 0;i < nb_elements;i++) {
7004
  test_node->name = elements[i];
7005
  if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
7006
      int j;
7007
7008
      for (j = 0; j < nb_valid_elements;j++)
7009
    if (xmlStrEqual(elements[i], names[j])) break;
7010
      names[nb_valid_elements++] = elements[i];
7011
      if (nb_valid_elements >= max) break;
7012
  }
7013
    }
7014
7015
    /*
7016
     * Restore the tree structure
7017
     */
7018
    if (prev) prev->next = prev_next;
7019
    if (next) next->prev = next_prev;
7020
    parent->children = parent_childs;
7021
    parent->last = parent_last;
7022
7023
    /*
7024
     * Free up the dummy node
7025
     */
7026
    test_node->name = name;
7027
    xmlFreeNode(test_node);
7028
7029
    return(nb_valid_elements);
7030
}
7031
#endif /* LIBXML_VALID_ENABLED */