Coverage Report

Created: 2025-07-11 06:48

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