Coverage Report

Created: 2023-11-19 06:13

/src/libxml2-2.11.5/valid.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * valid.c : part of the code use to do the DTD handling and the validity
3
 *           checking
4
 *
5
 * See Copyright for the status of this software.
6
 *
7
 * daniel@veillard.com
8
 */
9
10
#define IN_LIBXML
11
#include "libxml.h"
12
13
#include <string.h>
14
#include <stdlib.h>
15
16
#include <libxml/xmlmemory.h>
17
#include <libxml/hash.h>
18
#include <libxml/uri.h>
19
#include <libxml/valid.h>
20
#include <libxml/parser.h>
21
#include <libxml/parserInternals.h>
22
#include <libxml/xmlerror.h>
23
#include <libxml/list.h>
24
#include <libxml/globals.h>
25
26
#include "private/error.h"
27
#include "private/parser.h"
28
29
static xmlElementPtr
30
xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
31
                      int create);
32
/* #define DEBUG_VALID_ALGO */
33
/* #define DEBUG_REGEXP_ALGO */
34
35
#define TODO                \
36
    xmlGenericError(xmlGenericErrorContext,       \
37
      "Unimplemented block at %s:%d\n",       \
38
            __FILE__, __LINE__);
39
40
#ifdef LIBXML_VALID_ENABLED
41
static int
42
xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
43
                                  const xmlChar *value);
44
#endif
45
/************************************************************************
46
 *                  *
47
 *      Error handling routines       *
48
 *                  *
49
 ************************************************************************/
50
51
/**
52
 * xmlVErrMemory:
53
 * @ctxt:  an XML validation parser context
54
 * @extra:  extra information
55
 *
56
 * Handle an out of memory error
57
 */
58
static void
59
xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
60
0
{
61
0
    xmlGenericErrorFunc channel = NULL;
62
0
    xmlParserCtxtPtr pctxt = NULL;
63
0
    void *data = NULL;
64
65
0
    if (ctxt != NULL) {
66
0
        channel = ctxt->error;
67
0
        data = ctxt->userData;
68
  /* Look up flag to detect if it is part of a parsing
69
     context */
70
0
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
71
0
      pctxt = ctxt->userData;
72
0
  }
73
0
    }
74
0
    if (extra)
75
0
        __xmlRaiseError(NULL, channel, data,
76
0
                        pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
77
0
                        XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
78
0
                        "Memory allocation failed : %s\n", extra);
79
0
    else
80
0
        __xmlRaiseError(NULL, channel, data,
81
0
                        pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
82
0
                        XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
83
0
                        "Memory allocation failed\n");
84
0
}
85
86
/**
87
 * xmlErrValid:
88
 * @ctxt:  an XML validation parser context
89
 * @error:  the error number
90
 * @extra:  extra information
91
 *
92
 * Handle a validation error
93
 */
94
static void LIBXML_ATTR_FORMAT(3,0)
95
xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
96
            const char *msg, const char *extra)
97
0
{
98
0
    xmlGenericErrorFunc channel = NULL;
99
0
    xmlParserCtxtPtr pctxt = NULL;
100
0
    void *data = NULL;
101
102
0
    if (ctxt != NULL) {
103
0
        channel = ctxt->error;
104
0
        data = ctxt->userData;
105
  /* Look up flag to detect if it is part of a parsing
106
     context */
107
0
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
108
0
      pctxt = ctxt->userData;
109
0
  }
110
0
    }
111
0
    if (extra)
112
0
        __xmlRaiseError(NULL, channel, data,
113
0
                        pctxt, NULL, XML_FROM_VALID, error,
114
0
                        XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
115
0
                        msg, extra);
116
0
    else
117
0
        __xmlRaiseError(NULL, channel, data,
118
0
                        pctxt, NULL, XML_FROM_VALID, error,
119
0
                        XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
120
0
                        "%s", msg);
121
0
}
122
123
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
124
/**
125
 * xmlErrValidNode:
126
 * @ctxt:  an XML validation parser context
127
 * @node:  the node raising the error
128
 * @error:  the error number
129
 * @str1:  extra information
130
 * @str2:  extra information
131
 * @str3:  extra information
132
 *
133
 * Handle a validation error, provide contextual information
134
 */
135
static void LIBXML_ATTR_FORMAT(4,0)
136
xmlErrValidNode(xmlValidCtxtPtr ctxt,
137
                xmlNodePtr node, xmlParserErrors error,
138
                const char *msg, const xmlChar * str1,
139
                const xmlChar * str2, const xmlChar * str3)
140
0
{
141
0
    xmlStructuredErrorFunc schannel = NULL;
142
0
    xmlGenericErrorFunc channel = NULL;
143
0
    xmlParserCtxtPtr pctxt = NULL;
144
0
    void *data = NULL;
145
146
0
    if (ctxt != NULL) {
147
0
        channel = ctxt->error;
148
0
        data = ctxt->userData;
149
  /* Look up flag to detect if it is part of a parsing
150
     context */
151
0
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
152
0
      pctxt = ctxt->userData;
153
0
  }
154
0
    }
155
0
    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
156
0
                    XML_ERR_ERROR, NULL, 0,
157
0
                    (const char *) str1,
158
0
                    (const char *) str2,
159
0
                    (const char *) str3, 0, 0, msg, str1, str2, str3);
160
0
}
161
#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
162
163
#ifdef LIBXML_VALID_ENABLED
164
/**
165
 * xmlErrValidNodeNr:
166
 * @ctxt:  an XML validation parser context
167
 * @node:  the node raising the error
168
 * @error:  the error number
169
 * @str1:  extra information
170
 * @int2:  extra information
171
 * @str3:  extra information
172
 *
173
 * Handle a validation error, provide contextual information
174
 */
175
static void LIBXML_ATTR_FORMAT(4,0)
176
xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
177
                xmlNodePtr node, xmlParserErrors error,
178
                const char *msg, const xmlChar * str1,
179
                int int2, const xmlChar * str3)
180
0
{
181
0
    xmlStructuredErrorFunc schannel = NULL;
182
0
    xmlGenericErrorFunc channel = NULL;
183
0
    xmlParserCtxtPtr pctxt = NULL;
184
0
    void *data = NULL;
185
186
0
    if (ctxt != NULL) {
187
0
        channel = ctxt->error;
188
0
        data = ctxt->userData;
189
  /* Look up flag to detect if it is part of a parsing
190
     context */
191
0
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
192
0
      pctxt = ctxt->userData;
193
0
  }
194
0
    }
195
0
    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
196
0
                    XML_ERR_ERROR, NULL, 0,
197
0
                    (const char *) str1,
198
0
                    (const char *) str3,
199
0
                    NULL, int2, 0, msg, str1, int2, str3);
200
0
}
201
202
/**
203
 * xmlErrValidWarning:
204
 * @ctxt:  an XML validation parser context
205
 * @node:  the node raising the error
206
 * @error:  the error number
207
 * @str1:  extra information
208
 * @str2:  extra information
209
 * @str3:  extra information
210
 *
211
 * Handle a validation error, provide contextual information
212
 */
213
static void LIBXML_ATTR_FORMAT(4,0)
214
xmlErrValidWarning(xmlValidCtxtPtr ctxt,
215
                xmlNodePtr node, xmlParserErrors error,
216
                const char *msg, const xmlChar * str1,
217
                const xmlChar * str2, const xmlChar * str3)
218
0
{
219
0
    xmlStructuredErrorFunc schannel = NULL;
220
0
    xmlGenericErrorFunc channel = NULL;
221
0
    xmlParserCtxtPtr pctxt = NULL;
222
0
    void *data = NULL;
223
224
0
    if (ctxt != NULL) {
225
0
        channel = ctxt->warning;
226
0
        data = ctxt->userData;
227
  /* Look up flag to detect if it is part of a parsing
228
     context */
229
0
  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
230
0
      pctxt = ctxt->userData;
231
0
  }
232
0
    }
233
0
    __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
234
0
                    XML_ERR_WARNING, NULL, 0,
235
0
                    (const char *) str1,
236
0
                    (const char *) str2,
237
0
                    (const char *) str3, 0, 0, msg, str1, str2, str3);
238
0
}
239
240
241
242
#ifdef LIBXML_REGEXP_ENABLED
243
/*
244
 * If regexp are enabled we can do continuous validation without the
245
 * need of a tree to validate the content model. this is done in each
246
 * callbacks.
247
 * Each xmlValidState represent the validation state associated to the
248
 * set of nodes currently open from the document root to the current element.
249
 */
250
251
252
typedef struct _xmlValidState {
253
    xmlElementPtr  elemDecl;  /* pointer to the content model */
254
    xmlNodePtr           node;    /* pointer to the current node */
255
    xmlRegExecCtxtPtr    exec;    /* regexp runtime */
256
} _xmlValidState;
257
258
259
static int
260
0
vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
261
0
    if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
262
0
  ctxt->vstateMax = 10;
263
0
  ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
264
0
                  sizeof(ctxt->vstateTab[0]));
265
0
        if (ctxt->vstateTab == NULL) {
266
0
      xmlVErrMemory(ctxt, "malloc failed");
267
0
      return(-1);
268
0
  }
269
0
    }
270
271
0
    if (ctxt->vstateNr >= ctxt->vstateMax) {
272
0
        xmlValidState *tmp;
273
274
0
  tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
275
0
               2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
276
0
        if (tmp == NULL) {
277
0
      xmlVErrMemory(ctxt, "realloc failed");
278
0
      return(-1);
279
0
  }
280
0
  ctxt->vstateMax *= 2;
281
0
  ctxt->vstateTab = tmp;
282
0
    }
283
0
    ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
284
0
    ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
285
0
    ctxt->vstateTab[ctxt->vstateNr].node = node;
286
0
    if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
287
0
  if (elemDecl->contModel == NULL)
288
0
      xmlValidBuildContentModel(ctxt, elemDecl);
289
0
  if (elemDecl->contModel != NULL) {
290
0
      ctxt->vstateTab[ctxt->vstateNr].exec =
291
0
    xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
292
0
  } else {
293
0
      ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
294
0
      xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
295
0
                      XML_ERR_INTERNAL_ERROR,
296
0
          "Failed to build content model regexp for %s\n",
297
0
          node->name, NULL, NULL);
298
0
  }
299
0
    }
300
0
    return(ctxt->vstateNr++);
301
0
}
302
303
static int
304
0
vstateVPop(xmlValidCtxtPtr ctxt) {
305
0
    xmlElementPtr elemDecl;
306
307
0
    if (ctxt->vstateNr < 1) return(-1);
308
0
    ctxt->vstateNr--;
309
0
    elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
310
0
    ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
311
0
    ctxt->vstateTab[ctxt->vstateNr].node = NULL;
312
0
    if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
313
0
  xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
314
0
    }
315
0
    ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
316
0
    if (ctxt->vstateNr >= 1)
317
0
  ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
318
0
    else
319
0
  ctxt->vstate = NULL;
320
0
    return(ctxt->vstateNr);
321
0
}
322
323
#else /* not LIBXML_REGEXP_ENABLED */
324
/*
325
 * If regexp are not enabled, it uses a home made algorithm less
326
 * complex and easier to
327
 * debug/maintain than a generic NFA -> DFA state based algo. The
328
 * only restriction is on the deepness of the tree limited by the
329
 * size of the occurs bitfield
330
 *
331
 * this is the content of a saved state for rollbacks
332
 */
333
334
#define ROLLBACK_OR 0
335
#define ROLLBACK_PARENT 1
336
337
typedef struct _xmlValidState {
338
    xmlElementContentPtr cont;  /* pointer to the content model subtree */
339
    xmlNodePtr           node;  /* pointer to the current node in the list */
340
    long                 occurs;/* bitfield for multiple occurrences */
341
    unsigned char        depth; /* current depth in the overall tree */
342
    unsigned char        state; /* ROLLBACK_XXX */
343
} _xmlValidState;
344
345
#define MAX_RECURSE 25000
346
#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
347
#define CONT ctxt->vstate->cont
348
#define NODE ctxt->vstate->node
349
#define DEPTH ctxt->vstate->depth
350
#define OCCURS ctxt->vstate->occurs
351
#define STATE ctxt->vstate->state
352
353
#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
354
#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
355
356
#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
357
#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
358
359
static int
360
vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
361
      xmlNodePtr node, unsigned char depth, long occurs,
362
      unsigned char state) {
363
    int i = ctxt->vstateNr - 1;
364
365
    if (ctxt->vstateNr > MAX_RECURSE) {
366
  return(-1);
367
    }
368
    if (ctxt->vstateTab == NULL) {
369
  ctxt->vstateMax = 8;
370
  ctxt->vstateTab = (xmlValidState *) xmlMalloc(
371
         ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
372
  if (ctxt->vstateTab == NULL) {
373
      xmlVErrMemory(ctxt, "malloc failed");
374
      return(-1);
375
  }
376
    }
377
    if (ctxt->vstateNr >= ctxt->vstateMax) {
378
        xmlValidState *tmp;
379
380
        tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
381
               2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
382
        if (tmp == NULL) {
383
      xmlVErrMemory(ctxt, "malloc failed");
384
      return(-1);
385
  }
386
  ctxt->vstateMax *= 2;
387
  ctxt->vstateTab = tmp;
388
  ctxt->vstate = &ctxt->vstateTab[0];
389
    }
390
    /*
391
     * Don't push on the stack a state already here
392
     */
393
    if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
394
  (ctxt->vstateTab[i].node == node) &&
395
  (ctxt->vstateTab[i].depth == depth) &&
396
  (ctxt->vstateTab[i].occurs == occurs) &&
397
  (ctxt->vstateTab[i].state == state))
398
  return(ctxt->vstateNr);
399
    ctxt->vstateTab[ctxt->vstateNr].cont = cont;
400
    ctxt->vstateTab[ctxt->vstateNr].node = node;
401
    ctxt->vstateTab[ctxt->vstateNr].depth = depth;
402
    ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
403
    ctxt->vstateTab[ctxt->vstateNr].state = state;
404
    return(ctxt->vstateNr++);
405
}
406
407
static int
408
vstateVPop(xmlValidCtxtPtr ctxt) {
409
    if (ctxt->vstateNr <= 1) return(-1);
410
    ctxt->vstateNr--;
411
    ctxt->vstate = &ctxt->vstateTab[0];
412
    ctxt->vstate->cont =  ctxt->vstateTab[ctxt->vstateNr].cont;
413
    ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
414
    ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
415
    ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
416
    ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
417
    return(ctxt->vstateNr);
418
}
419
420
#endif /* LIBXML_REGEXP_ENABLED */
421
422
static int
423
nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
424
0
{
425
0
    if (ctxt->nodeMax <= 0) {
426
0
        ctxt->nodeMax = 4;
427
0
        ctxt->nodeTab =
428
0
            (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
429
0
                                     sizeof(ctxt->nodeTab[0]));
430
0
        if (ctxt->nodeTab == NULL) {
431
0
      xmlVErrMemory(ctxt, "malloc failed");
432
0
            ctxt->nodeMax = 0;
433
0
            return (0);
434
0
        }
435
0
    }
436
0
    if (ctxt->nodeNr >= ctxt->nodeMax) {
437
0
        xmlNodePtr *tmp;
438
0
        tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
439
0
            ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
440
0
        if (tmp == NULL) {
441
0
      xmlVErrMemory(ctxt, "realloc failed");
442
0
            return (0);
443
0
        }
444
0
        ctxt->nodeMax *= 2;
445
0
  ctxt->nodeTab = tmp;
446
0
    }
447
0
    ctxt->nodeTab[ctxt->nodeNr] = value;
448
0
    ctxt->node = value;
449
0
    return (ctxt->nodeNr++);
450
0
}
451
static xmlNodePtr
452
nodeVPop(xmlValidCtxtPtr ctxt)
453
0
{
454
0
    xmlNodePtr ret;
455
456
0
    if (ctxt->nodeNr <= 0)
457
0
        return (NULL);
458
0
    ctxt->nodeNr--;
459
0
    if (ctxt->nodeNr > 0)
460
0
        ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
461
0
    else
462
0
        ctxt->node = NULL;
463
0
    ret = ctxt->nodeTab[ctxt->nodeNr];
464
0
    ctxt->nodeTab[ctxt->nodeNr] = NULL;
465
0
    return (ret);
466
0
}
467
468
#ifdef DEBUG_VALID_ALGO
469
static void
470
xmlValidPrintNode(xmlNodePtr cur) {
471
    if (cur == NULL) {
472
  xmlGenericError(xmlGenericErrorContext, "null");
473
  return;
474
    }
475
    switch (cur->type) {
476
  case XML_ELEMENT_NODE:
477
      xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
478
      break;
479
  case XML_TEXT_NODE:
480
      xmlGenericError(xmlGenericErrorContext, "text ");
481
      break;
482
  case XML_CDATA_SECTION_NODE:
483
      xmlGenericError(xmlGenericErrorContext, "cdata ");
484
      break;
485
  case XML_ENTITY_REF_NODE:
486
      xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
487
      break;
488
  case XML_PI_NODE:
489
      xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
490
      break;
491
  case XML_COMMENT_NODE:
492
      xmlGenericError(xmlGenericErrorContext, "comment ");
493
      break;
494
  case XML_ATTRIBUTE_NODE:
495
      xmlGenericError(xmlGenericErrorContext, "?attr? ");
496
      break;
497
  case XML_ENTITY_NODE:
498
      xmlGenericError(xmlGenericErrorContext, "?ent? ");
499
      break;
500
  case XML_DOCUMENT_NODE:
501
      xmlGenericError(xmlGenericErrorContext, "?doc? ");
502
      break;
503
  case XML_DOCUMENT_TYPE_NODE:
504
      xmlGenericError(xmlGenericErrorContext, "?doctype? ");
505
      break;
506
  case XML_DOCUMENT_FRAG_NODE:
507
      xmlGenericError(xmlGenericErrorContext, "?frag? ");
508
      break;
509
  case XML_NOTATION_NODE:
510
      xmlGenericError(xmlGenericErrorContext, "?nota? ");
511
      break;
512
  case XML_HTML_DOCUMENT_NODE:
513
      xmlGenericError(xmlGenericErrorContext, "?html? ");
514
      break;
515
  case XML_DTD_NODE:
516
      xmlGenericError(xmlGenericErrorContext, "?dtd? ");
517
      break;
518
  case XML_ELEMENT_DECL:
519
      xmlGenericError(xmlGenericErrorContext, "?edecl? ");
520
      break;
521
  case XML_ATTRIBUTE_DECL:
522
      xmlGenericError(xmlGenericErrorContext, "?adecl? ");
523
      break;
524
  case XML_ENTITY_DECL:
525
      xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
526
      break;
527
  case XML_NAMESPACE_DECL:
528
      xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
529
      break;
530
  case XML_XINCLUDE_START:
531
      xmlGenericError(xmlGenericErrorContext, "incstart ");
532
      break;
533
  case XML_XINCLUDE_END:
534
      xmlGenericError(xmlGenericErrorContext, "incend ");
535
      break;
536
    }
537
}
538
539
static void
540
xmlValidPrintNodeList(xmlNodePtr cur) {
541
    if (cur == NULL)
542
  xmlGenericError(xmlGenericErrorContext, "null ");
543
    while (cur != NULL) {
544
  xmlValidPrintNode(cur);
545
  cur = cur->next;
546
    }
547
}
548
549
static void
550
xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
551
    char expr[5000];
552
553
    expr[0] = 0;
554
    xmlGenericError(xmlGenericErrorContext, "valid: ");
555
    xmlValidPrintNodeList(cur);
556
    xmlGenericError(xmlGenericErrorContext, "against ");
557
    xmlSnprintfElementContent(expr, 5000, cont, 1);
558
    xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
559
}
560
561
static void
562
xmlValidDebugState(xmlValidStatePtr state) {
563
    xmlGenericError(xmlGenericErrorContext, "(");
564
    if (state->cont == NULL)
565
  xmlGenericError(xmlGenericErrorContext, "null,");
566
    else
567
  switch (state->cont->type) {
568
            case XML_ELEMENT_CONTENT_PCDATA:
569
    xmlGenericError(xmlGenericErrorContext, "pcdata,");
570
    break;
571
            case XML_ELEMENT_CONTENT_ELEMENT:
572
    xmlGenericError(xmlGenericErrorContext, "%s,",
573
              state->cont->name);
574
    break;
575
            case XML_ELEMENT_CONTENT_SEQ:
576
    xmlGenericError(xmlGenericErrorContext, "seq,");
577
    break;
578
            case XML_ELEMENT_CONTENT_OR:
579
    xmlGenericError(xmlGenericErrorContext, "or,");
580
    break;
581
  }
582
    xmlValidPrintNode(state->node);
583
    xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
584
      state->depth, state->occurs, state->state);
585
}
586
587
static void
588
xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
589
    int i, j;
590
591
    xmlGenericError(xmlGenericErrorContext, "state: ");
592
    xmlValidDebugState(ctxt->vstate);
593
    xmlGenericError(xmlGenericErrorContext, " stack: %d ",
594
      ctxt->vstateNr - 1);
595
    for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
596
  xmlValidDebugState(&ctxt->vstateTab[j]);
597
    xmlGenericError(xmlGenericErrorContext, "\n");
598
}
599
600
/*****
601
#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
602
 *****/
603
604
#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
605
#define DEBUG_VALID_MSG(m)          \
606
    xmlGenericError(xmlGenericErrorContext, "%s\n", m);
607
608
#else
609
#define DEBUG_VALID_STATE(n,c)
610
#define DEBUG_VALID_MSG(m)
611
#endif
612
613
/* TODO: use hash table for accesses to elem and attribute definitions */
614
615
616
#define CHECK_DTD           \
617
0
   if (doc == NULL) return(0);         \
618
0
   else if ((doc->intSubset == NULL) &&       \
619
0
      (doc->extSubset == NULL)) return(0)
620
621
#ifdef LIBXML_REGEXP_ENABLED
622
623
/************************************************************************
624
 *                  *
625
 *    Content model validation based on the regexps   *
626
 *                  *
627
 ************************************************************************/
628
629
/**
630
 * xmlValidBuildAContentModel:
631
 * @content:  the content model
632
 * @ctxt:  the schema parser context
633
 * @name:  the element name whose content is being built
634
 *
635
 * Generate the automata sequence needed for that type
636
 *
637
 * Returns 1 if successful or 0 in case of error.
638
 */
639
static int
640
xmlValidBuildAContentModel(xmlElementContentPtr content,
641
               xmlValidCtxtPtr ctxt,
642
0
               const xmlChar *name) {
643
0
    if (content == NULL) {
644
0
  xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
645
0
      "Found NULL content in content model of %s\n",
646
0
      name, NULL, NULL);
647
0
  return(0);
648
0
    }
649
0
    switch (content->type) {
650
0
  case XML_ELEMENT_CONTENT_PCDATA:
651
0
      xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
652
0
          "Found PCDATA in content model of %s\n",
653
0
                name, NULL, NULL);
654
0
      return(0);
655
0
      break;
656
0
  case XML_ELEMENT_CONTENT_ELEMENT: {
657
0
      xmlAutomataStatePtr oldstate = ctxt->state;
658
0
      xmlChar fn[50];
659
0
      xmlChar *fullname;
660
661
0
      fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
662
0
      if (fullname == NULL) {
663
0
          xmlVErrMemory(ctxt, "Building content model");
664
0
    return(0);
665
0
      }
666
667
0
      switch (content->ocur) {
668
0
    case XML_ELEMENT_CONTENT_ONCE:
669
0
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
670
0
          ctxt->state, NULL, fullname, NULL);
671
0
        break;
672
0
    case XML_ELEMENT_CONTENT_OPT:
673
0
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
674
0
          ctxt->state, NULL, fullname, NULL);
675
0
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
676
0
        break;
677
0
    case XML_ELEMENT_CONTENT_PLUS:
678
0
        ctxt->state = xmlAutomataNewTransition(ctxt->am,
679
0
          ctxt->state, NULL, fullname, NULL);
680
0
        xmlAutomataNewTransition(ctxt->am, ctxt->state,
681
0
                           ctxt->state, fullname, NULL);
682
0
        break;
683
0
    case XML_ELEMENT_CONTENT_MULT:
684
0
        ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
685
0
              ctxt->state, NULL);
686
0
        xmlAutomataNewTransition(ctxt->am,
687
0
          ctxt->state, ctxt->state, fullname, NULL);
688
0
        break;
689
0
      }
690
0
      if ((fullname != fn) && (fullname != content->name))
691
0
    xmlFree(fullname);
692
0
      break;
693
0
  }
694
0
  case XML_ELEMENT_CONTENT_SEQ: {
695
0
      xmlAutomataStatePtr oldstate, oldend;
696
0
      xmlElementContentOccur ocur;
697
698
      /*
699
       * Simply iterate over the content
700
       */
701
0
      oldstate = ctxt->state;
702
0
      ocur = content->ocur;
703
0
      if (ocur != XML_ELEMENT_CONTENT_ONCE) {
704
0
    ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
705
0
    oldstate = ctxt->state;
706
0
      }
707
0
      do {
708
0
    xmlValidBuildAContentModel(content->c1, ctxt, name);
709
0
    content = content->c2;
710
0
      } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
711
0
         (content->ocur == XML_ELEMENT_CONTENT_ONCE));
712
0
      xmlValidBuildAContentModel(content, ctxt, name);
713
0
      oldend = ctxt->state;
714
0
      ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
715
0
      switch (ocur) {
716
0
    case XML_ELEMENT_CONTENT_ONCE:
717
0
        break;
718
0
    case XML_ELEMENT_CONTENT_OPT:
719
0
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
720
0
        break;
721
0
    case XML_ELEMENT_CONTENT_MULT:
722
0
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
723
0
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
724
0
        break;
725
0
    case XML_ELEMENT_CONTENT_PLUS:
726
0
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
727
0
        break;
728
0
      }
729
0
      break;
730
0
  }
731
0
  case XML_ELEMENT_CONTENT_OR: {
732
0
      xmlAutomataStatePtr oldstate, oldend;
733
0
      xmlElementContentOccur ocur;
734
735
0
      ocur = content->ocur;
736
0
      if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
737
0
    (ocur == XML_ELEMENT_CONTENT_MULT)) {
738
0
    ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
739
0
      ctxt->state, NULL);
740
0
      }
741
0
      oldstate = ctxt->state;
742
0
      oldend = xmlAutomataNewState(ctxt->am);
743
744
      /*
745
       * iterate over the subtypes and remerge the end with an
746
       * epsilon transition
747
       */
748
0
      do {
749
0
    ctxt->state = oldstate;
750
0
    xmlValidBuildAContentModel(content->c1, ctxt, name);
751
0
    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
752
0
    content = content->c2;
753
0
      } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
754
0
         (content->ocur == XML_ELEMENT_CONTENT_ONCE));
755
0
      ctxt->state = oldstate;
756
0
      xmlValidBuildAContentModel(content, ctxt, name);
757
0
      xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
758
0
      ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
759
0
      switch (ocur) {
760
0
    case XML_ELEMENT_CONTENT_ONCE:
761
0
        break;
762
0
    case XML_ELEMENT_CONTENT_OPT:
763
0
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
764
0
        break;
765
0
    case XML_ELEMENT_CONTENT_MULT:
766
0
        xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
767
0
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
768
0
        break;
769
0
    case XML_ELEMENT_CONTENT_PLUS:
770
0
        xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
771
0
        break;
772
0
      }
773
0
      break;
774
0
  }
775
0
  default:
776
0
      xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
777
0
                  "ContentModel broken for element %s\n",
778
0
      (const char *) name);
779
0
      return(0);
780
0
    }
781
0
    return(1);
782
0
}
783
/**
784
 * xmlValidBuildContentModel:
785
 * @ctxt:  a validation context
786
 * @elem:  an element declaration node
787
 *
788
 * (Re)Build the automata associated to the content model of this
789
 * element
790
 *
791
 * Returns 1 in case of success, 0 in case of error
792
 */
793
int
794
0
xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
795
796
0
    if ((ctxt == NULL) || (elem == NULL))
797
0
  return(0);
798
0
    if (elem->type != XML_ELEMENT_DECL)
799
0
  return(0);
800
0
    if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
801
0
  return(1);
802
    /* TODO: should we rebuild in this case ? */
803
0
    if (elem->contModel != NULL) {
804
0
  if (!xmlRegexpIsDeterminist(elem->contModel)) {
805
0
      ctxt->valid = 0;
806
0
      return(0);
807
0
  }
808
0
  return(1);
809
0
    }
810
811
0
    ctxt->am = xmlNewAutomata();
812
0
    if (ctxt->am == NULL) {
813
0
  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
814
0
                  XML_ERR_INTERNAL_ERROR,
815
0
                  "Cannot create automata for element %s\n",
816
0
            elem->name, NULL, NULL);
817
0
  return(0);
818
0
    }
819
0
    ctxt->state = xmlAutomataGetInitState(ctxt->am);
820
0
    xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
821
0
    xmlAutomataSetFinalState(ctxt->am, ctxt->state);
822
0
    elem->contModel = xmlAutomataCompile(ctxt->am);
823
0
    if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
824
0
  char expr[5000];
825
0
  expr[0] = 0;
826
0
  xmlSnprintfElementContent(expr, 5000, elem->content, 1);
827
0
  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
828
0
                  XML_DTD_CONTENT_NOT_DETERMINIST,
829
0
         "Content model of %s is not deterministic: %s\n",
830
0
         elem->name, BAD_CAST expr, NULL);
831
#ifdef DEBUG_REGEXP_ALGO
832
        xmlRegexpPrint(stderr, elem->contModel);
833
#endif
834
0
        ctxt->valid = 0;
835
0
  ctxt->state = NULL;
836
0
  xmlFreeAutomata(ctxt->am);
837
0
  ctxt->am = NULL;
838
0
  return(0);
839
0
    }
840
0
    ctxt->state = NULL;
841
0
    xmlFreeAutomata(ctxt->am);
842
0
    ctxt->am = NULL;
843
0
    return(1);
844
0
}
845
846
#endif /* LIBXML_REGEXP_ENABLED */
847
848
/****************************************************************
849
 *                *
850
 *  Util functions for data allocation/deallocation   *
851
 *                *
852
 ****************************************************************/
853
854
/**
855
 * xmlNewValidCtxt:
856
 *
857
 * Allocate a validation context structure.
858
 *
859
 * Returns NULL if not, otherwise the new validation context structure
860
 */
861
0
xmlValidCtxtPtr xmlNewValidCtxt(void) {
862
0
    xmlValidCtxtPtr ret;
863
864
0
    if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
865
0
  xmlVErrMemory(NULL, "malloc failed");
866
0
  return (NULL);
867
0
    }
868
869
0
    (void) memset(ret, 0, sizeof (xmlValidCtxt));
870
871
0
    return (ret);
872
0
}
873
874
/**
875
 * xmlFreeValidCtxt:
876
 * @cur:  the validation context to free
877
 *
878
 * Free a validation context structure.
879
 */
880
void
881
0
xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
882
0
    if (cur == NULL)
883
0
        return;
884
0
    if (cur->vstateTab != NULL)
885
0
        xmlFree(cur->vstateTab);
886
0
    if (cur->nodeTab != NULL)
887
0
        xmlFree(cur->nodeTab);
888
0
    xmlFree(cur);
889
0
}
890
891
#endif /* LIBXML_VALID_ENABLED */
892
893
/**
894
 * xmlNewDocElementContent:
895
 * @doc:  the document
896
 * @name:  the subelement name or NULL
897
 * @type:  the type of element content decl
898
 *
899
 * Allocate an element content structure for the document.
900
 *
901
 * Returns NULL if not, otherwise the new element content structure
902
 */
903
xmlElementContentPtr
904
xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
905
15.2k
                        xmlElementContentType type) {
906
15.2k
    xmlElementContentPtr ret;
907
15.2k
    xmlDictPtr dict = NULL;
908
909
15.2k
    if (doc != NULL)
910
296
        dict = doc->dict;
911
912
15.2k
    switch(type) {
913
7.64k
  case XML_ELEMENT_CONTENT_ELEMENT:
914
7.64k
      if (name == NULL) {
915
0
          xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
916
0
      "xmlNewElementContent : name == NULL !\n",
917
0
      NULL);
918
0
      }
919
7.64k
      break;
920
706
        case XML_ELEMENT_CONTENT_PCDATA:
921
2.30k
  case XML_ELEMENT_CONTENT_SEQ:
922
7.59k
  case XML_ELEMENT_CONTENT_OR:
923
7.59k
      if (name != NULL) {
924
0
          xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
925
0
      "xmlNewElementContent : name != NULL !\n",
926
0
      NULL);
927
0
      }
928
7.59k
      break;
929
0
  default:
930
0
      xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
931
0
        "Internal: ELEMENT content corrupted invalid type\n",
932
0
        NULL);
933
0
      return(NULL);
934
15.2k
    }
935
15.2k
    ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
936
15.2k
    if (ret == NULL) {
937
0
  xmlVErrMemory(NULL, "malloc failed");
938
0
  return(NULL);
939
0
    }
940
15.2k
    memset(ret, 0, sizeof(xmlElementContent));
941
15.2k
    ret->type = type;
942
15.2k
    ret->ocur = XML_ELEMENT_CONTENT_ONCE;
943
15.2k
    if (name != NULL) {
944
7.64k
        int l;
945
7.64k
  const xmlChar *tmp;
946
947
7.64k
  tmp = xmlSplitQName3(name, &l);
948
7.64k
  if (tmp == NULL) {
949
7.22k
      if (dict == NULL)
950
7.22k
    ret->name = xmlStrdup(name);
951
0
      else
952
0
          ret->name = xmlDictLookup(dict, name, -1);
953
7.22k
  } else {
954
420
      if (dict == NULL) {
955
420
    ret->prefix = xmlStrndup(name, l);
956
420
    ret->name = xmlStrdup(tmp);
957
420
      } else {
958
0
          ret->prefix = xmlDictLookup(dict, name, l);
959
0
    ret->name = xmlDictLookup(dict, tmp, -1);
960
0
      }
961
420
  }
962
7.64k
    }
963
15.2k
    return(ret);
964
15.2k
}
965
966
/**
967
 * xmlNewElementContent:
968
 * @name:  the subelement name or NULL
969
 * @type:  the type of element content decl
970
 *
971
 * Allocate an element content structure.
972
 * Deprecated in favor of xmlNewDocElementContent
973
 *
974
 * Returns NULL if not, otherwise the new element content structure
975
 */
976
xmlElementContentPtr
977
0
xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
978
0
    return(xmlNewDocElementContent(NULL, name, type));
979
0
}
980
981
/**
982
 * xmlCopyDocElementContent:
983
 * @doc:  the document owning the element declaration
984
 * @cur:  An element content pointer.
985
 *
986
 * Build a copy of an element content description.
987
 *
988
 * Returns the new xmlElementContentPtr or NULL in case of error.
989
 */
990
xmlElementContentPtr
991
0
xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
992
0
    xmlElementContentPtr ret = NULL, prev = NULL, tmp;
993
0
    xmlDictPtr dict = NULL;
994
995
0
    if (cur == NULL) return(NULL);
996
997
0
    if (doc != NULL)
998
0
        dict = doc->dict;
999
1000
0
    ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1001
0
    if (ret == NULL) {
1002
0
  xmlVErrMemory(NULL, "malloc failed");
1003
0
  return(NULL);
1004
0
    }
1005
0
    memset(ret, 0, sizeof(xmlElementContent));
1006
0
    ret->type = cur->type;
1007
0
    ret->ocur = cur->ocur;
1008
0
    if (cur->name != NULL) {
1009
0
  if (dict)
1010
0
      ret->name = xmlDictLookup(dict, cur->name, -1);
1011
0
  else
1012
0
      ret->name = xmlStrdup(cur->name);
1013
0
    }
1014
1015
0
    if (cur->prefix != NULL) {
1016
0
  if (dict)
1017
0
      ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1018
0
  else
1019
0
      ret->prefix = xmlStrdup(cur->prefix);
1020
0
    }
1021
0
    if (cur->c1 != NULL)
1022
0
        ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1023
0
    if (ret->c1 != NULL)
1024
0
  ret->c1->parent = ret;
1025
0
    if (cur->c2 != NULL) {
1026
0
        prev = ret;
1027
0
  cur = cur->c2;
1028
0
  while (cur != NULL) {
1029
0
      tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1030
0
      if (tmp == NULL) {
1031
0
    xmlVErrMemory(NULL, "malloc failed");
1032
0
    return(ret);
1033
0
      }
1034
0
      memset(tmp, 0, sizeof(xmlElementContent));
1035
0
      tmp->type = cur->type;
1036
0
      tmp->ocur = cur->ocur;
1037
0
      prev->c2 = tmp;
1038
0
      tmp->parent = prev;
1039
0
      if (cur->name != NULL) {
1040
0
    if (dict)
1041
0
        tmp->name = xmlDictLookup(dict, cur->name, -1);
1042
0
    else
1043
0
        tmp->name = xmlStrdup(cur->name);
1044
0
      }
1045
1046
0
      if (cur->prefix != NULL) {
1047
0
    if (dict)
1048
0
        tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1049
0
    else
1050
0
        tmp->prefix = xmlStrdup(cur->prefix);
1051
0
      }
1052
0
      if (cur->c1 != NULL)
1053
0
          tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1054
0
      if (tmp->c1 != NULL)
1055
0
    tmp->c1->parent = tmp;
1056
0
      prev = tmp;
1057
0
      cur = cur->c2;
1058
0
  }
1059
0
    }
1060
0
    return(ret);
1061
0
}
1062
1063
/**
1064
 * xmlCopyElementContent:
1065
 * @cur:  An element content pointer.
1066
 *
1067
 * Build a copy of an element content description.
1068
 * Deprecated, use xmlCopyDocElementContent instead
1069
 *
1070
 * Returns the new xmlElementContentPtr or NULL in case of error.
1071
 */
1072
xmlElementContentPtr
1073
0
xmlCopyElementContent(xmlElementContentPtr cur) {
1074
0
    return(xmlCopyDocElementContent(NULL, cur));
1075
0
}
1076
1077
/**
1078
 * xmlFreeDocElementContent:
1079
 * @doc: the document owning the element declaration
1080
 * @cur:  the element content tree to free
1081
 *
1082
 * Free an element content structure. The whole subtree is removed.
1083
 */
1084
void
1085
4.47k
xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1086
4.47k
    xmlDictPtr dict = NULL;
1087
4.47k
    size_t depth = 0;
1088
1089
4.47k
    if (cur == NULL)
1090
46
        return;
1091
4.42k
    if (doc != NULL)
1092
147
        dict = doc->dict;
1093
1094
15.2k
    while (1) {
1095
15.2k
        xmlElementContentPtr parent;
1096
1097
22.1k
        while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
1098
6.88k
            cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
1099
6.88k
            depth += 1;
1100
6.88k
        }
1101
1102
15.2k
  switch (cur->type) {
1103
706
      case XML_ELEMENT_CONTENT_PCDATA:
1104
8.35k
      case XML_ELEMENT_CONTENT_ELEMENT:
1105
9.95k
      case XML_ELEMENT_CONTENT_SEQ:
1106
15.2k
      case XML_ELEMENT_CONTENT_OR:
1107
15.2k
    break;
1108
0
      default:
1109
0
    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1110
0
      "Internal: ELEMENT content corrupted invalid type\n",
1111
0
      NULL);
1112
0
    return;
1113
15.2k
  }
1114
15.2k
  if (dict) {
1115
0
      if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1116
0
          xmlFree((xmlChar *) cur->name);
1117
0
      if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1118
0
          xmlFree((xmlChar *) cur->prefix);
1119
15.2k
  } else {
1120
15.2k
      if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1121
15.2k
      if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1122
15.2k
  }
1123
15.2k
        parent = cur->parent;
1124
15.2k
        if ((depth == 0) || (parent == NULL)) {
1125
4.42k
            xmlFree(cur);
1126
4.42k
            break;
1127
4.42k
        }
1128
10.8k
        if (cur == parent->c1)
1129
6.88k
            parent->c1 = NULL;
1130
3.92k
        else
1131
3.92k
            parent->c2 = NULL;
1132
10.8k
  xmlFree(cur);
1133
1134
10.8k
        if (parent->c2 != NULL) {
1135
3.92k
      cur = parent->c2;
1136
6.88k
        } else {
1137
6.88k
            depth -= 1;
1138
6.88k
            cur = parent;
1139
6.88k
        }
1140
10.8k
    }
1141
4.42k
}
1142
1143
/**
1144
 * xmlFreeElementContent:
1145
 * @cur:  the element content tree to free
1146
 *
1147
 * Free an element content structure. The whole subtree is removed.
1148
 * Deprecated, use xmlFreeDocElementContent instead
1149
 */
1150
void
1151
0
xmlFreeElementContent(xmlElementContentPtr cur) {
1152
0
    xmlFreeDocElementContent(NULL, cur);
1153
0
}
1154
1155
#ifdef LIBXML_OUTPUT_ENABLED
1156
/**
1157
 * xmlDumpElementOccur:
1158
 * @buf:  An XML buffer
1159
 * @cur:  An element table
1160
 *
1161
 * Dump the occurrence operator of an element.
1162
 */
1163
static void
1164
0
xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
1165
0
    switch (cur->ocur) {
1166
0
        case XML_ELEMENT_CONTENT_ONCE:
1167
0
            break;
1168
0
        case XML_ELEMENT_CONTENT_OPT:
1169
0
            xmlBufferWriteChar(buf, "?");
1170
0
            break;
1171
0
        case XML_ELEMENT_CONTENT_MULT:
1172
0
            xmlBufferWriteChar(buf, "*");
1173
0
            break;
1174
0
        case XML_ELEMENT_CONTENT_PLUS:
1175
0
            xmlBufferWriteChar(buf, "+");
1176
0
            break;
1177
0
    }
1178
0
}
1179
1180
/**
1181
 * xmlDumpElementContent:
1182
 * @buf:  An XML buffer
1183
 * @content:  An element table
1184
 *
1185
 * This will dump the content of the element table as an XML DTD definition
1186
 */
1187
static void
1188
0
xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
1189
0
    xmlElementContentPtr cur;
1190
1191
0
    if (content == NULL) return;
1192
1193
0
    xmlBufferWriteChar(buf, "(");
1194
0
    cur = content;
1195
1196
0
    do {
1197
0
        if (cur == NULL) return;
1198
1199
0
        switch (cur->type) {
1200
0
            case XML_ELEMENT_CONTENT_PCDATA:
1201
0
                xmlBufferWriteChar(buf, "#PCDATA");
1202
0
                break;
1203
0
            case XML_ELEMENT_CONTENT_ELEMENT:
1204
0
                if (cur->prefix != NULL) {
1205
0
                    xmlBufferWriteCHAR(buf, cur->prefix);
1206
0
                    xmlBufferWriteChar(buf, ":");
1207
0
                }
1208
0
                xmlBufferWriteCHAR(buf, cur->name);
1209
0
                break;
1210
0
            case XML_ELEMENT_CONTENT_SEQ:
1211
0
            case XML_ELEMENT_CONTENT_OR:
1212
0
                if ((cur != content) &&
1213
0
                    (cur->parent != NULL) &&
1214
0
                    ((cur->type != cur->parent->type) ||
1215
0
                     (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1216
0
                    xmlBufferWriteChar(buf, "(");
1217
0
                cur = cur->c1;
1218
0
                continue;
1219
0
            default:
1220
0
                xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1221
0
                        "Internal: ELEMENT cur corrupted invalid type\n",
1222
0
                        NULL);
1223
0
        }
1224
1225
0
        while (cur != content) {
1226
0
            xmlElementContentPtr parent = cur->parent;
1227
1228
0
            if (parent == NULL) return;
1229
1230
0
            if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
1231
0
                 (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
1232
0
                ((cur->type != parent->type) ||
1233
0
                 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1234
0
                xmlBufferWriteChar(buf, ")");
1235
0
            xmlDumpElementOccur(buf, cur);
1236
1237
0
            if (cur == parent->c1) {
1238
0
                if (parent->type == XML_ELEMENT_CONTENT_SEQ)
1239
0
                    xmlBufferWriteChar(buf, " , ");
1240
0
                else if (parent->type == XML_ELEMENT_CONTENT_OR)
1241
0
                    xmlBufferWriteChar(buf, " | ");
1242
1243
0
                cur = parent->c2;
1244
0
                break;
1245
0
            }
1246
1247
0
            cur = parent;
1248
0
        }
1249
0
    } while (cur != content);
1250
1251
0
    xmlBufferWriteChar(buf, ")");
1252
0
    xmlDumpElementOccur(buf, content);
1253
0
}
1254
1255
/**
1256
 * xmlSprintfElementContent:
1257
 * @buf:  an output buffer
1258
 * @content:  An element table
1259
 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1260
 *
1261
 * Deprecated, unsafe, use xmlSnprintfElementContent
1262
 */
1263
void
1264
xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1265
                   xmlElementContentPtr content ATTRIBUTE_UNUSED,
1266
0
       int englob ATTRIBUTE_UNUSED) {
1267
0
}
1268
#endif /* LIBXML_OUTPUT_ENABLED */
1269
1270
/**
1271
 * xmlSnprintfElementContent:
1272
 * @buf:  an output buffer
1273
 * @size:  the buffer size
1274
 * @content:  An element table
1275
 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1276
 *
1277
 * This will dump the content of the element content definition
1278
 * Intended just for the debug routine
1279
 */
1280
void
1281
0
xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1282
0
    int len;
1283
1284
0
    if (content == NULL) return;
1285
0
    len = strlen(buf);
1286
0
    if (size - len < 50) {
1287
0
  if ((size - len > 4) && (buf[len - 1] != '.'))
1288
0
      strcat(buf, " ...");
1289
0
  return;
1290
0
    }
1291
0
    if (englob) strcat(buf, "(");
1292
0
    switch (content->type) {
1293
0
        case XML_ELEMENT_CONTENT_PCDATA:
1294
0
            strcat(buf, "#PCDATA");
1295
0
      break;
1296
0
  case XML_ELEMENT_CONTENT_ELEMENT: {
1297
0
            int qnameLen = xmlStrlen(content->name);
1298
1299
0
      if (content->prefix != NULL)
1300
0
                qnameLen += xmlStrlen(content->prefix) + 1;
1301
0
      if (size - len < qnameLen + 10) {
1302
0
    strcat(buf, " ...");
1303
0
    return;
1304
0
      }
1305
0
      if (content->prefix != NULL) {
1306
0
    strcat(buf, (char *) content->prefix);
1307
0
    strcat(buf, ":");
1308
0
      }
1309
0
      if (content->name != NULL)
1310
0
    strcat(buf, (char *) content->name);
1311
0
      break;
1312
0
        }
1313
0
  case XML_ELEMENT_CONTENT_SEQ:
1314
0
      if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1315
0
          (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1316
0
    xmlSnprintfElementContent(buf, size, content->c1, 1);
1317
0
      else
1318
0
    xmlSnprintfElementContent(buf, size, content->c1, 0);
1319
0
      len = strlen(buf);
1320
0
      if (size - len < 50) {
1321
0
    if ((size - len > 4) && (buf[len - 1] != '.'))
1322
0
        strcat(buf, " ...");
1323
0
    return;
1324
0
      }
1325
0
            strcat(buf, " , ");
1326
0
      if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1327
0
     (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1328
0
    (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1329
0
    xmlSnprintfElementContent(buf, size, content->c2, 1);
1330
0
      else
1331
0
    xmlSnprintfElementContent(buf, size, content->c2, 0);
1332
0
      break;
1333
0
  case XML_ELEMENT_CONTENT_OR:
1334
0
      if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1335
0
          (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1336
0
    xmlSnprintfElementContent(buf, size, content->c1, 1);
1337
0
      else
1338
0
    xmlSnprintfElementContent(buf, size, content->c1, 0);
1339
0
      len = strlen(buf);
1340
0
      if (size - len < 50) {
1341
0
    if ((size - len > 4) && (buf[len - 1] != '.'))
1342
0
        strcat(buf, " ...");
1343
0
    return;
1344
0
      }
1345
0
            strcat(buf, " | ");
1346
0
      if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1347
0
     (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1348
0
    (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1349
0
    xmlSnprintfElementContent(buf, size, content->c2, 1);
1350
0
      else
1351
0
    xmlSnprintfElementContent(buf, size, content->c2, 0);
1352
0
      break;
1353
0
    }
1354
0
    if (size - strlen(buf) <= 2) return;
1355
0
    if (englob)
1356
0
        strcat(buf, ")");
1357
0
    switch (content->ocur) {
1358
0
        case XML_ELEMENT_CONTENT_ONCE:
1359
0
      break;
1360
0
        case XML_ELEMENT_CONTENT_OPT:
1361
0
      strcat(buf, "?");
1362
0
      break;
1363
0
        case XML_ELEMENT_CONTENT_MULT:
1364
0
      strcat(buf, "*");
1365
0
      break;
1366
0
        case XML_ELEMENT_CONTENT_PLUS:
1367
0
      strcat(buf, "+");
1368
0
      break;
1369
0
    }
1370
0
}
1371
1372
/****************************************************************
1373
 *                *
1374
 *  Registration of DTD declarations      *
1375
 *                *
1376
 ****************************************************************/
1377
1378
/**
1379
 * xmlFreeElement:
1380
 * @elem:  An element
1381
 *
1382
 * Deallocate the memory used by an element definition
1383
 */
1384
static void
1385
0
xmlFreeElement(xmlElementPtr elem) {
1386
0
    if (elem == NULL) return;
1387
0
    xmlUnlinkNode((xmlNodePtr) elem);
1388
0
    xmlFreeDocElementContent(elem->doc, elem->content);
1389
0
    if (elem->name != NULL)
1390
0
  xmlFree((xmlChar *) elem->name);
1391
0
    if (elem->prefix != NULL)
1392
0
  xmlFree((xmlChar *) elem->prefix);
1393
0
#ifdef LIBXML_REGEXP_ENABLED
1394
0
    if (elem->contModel != NULL)
1395
0
  xmlRegFreeRegexp(elem->contModel);
1396
0
#endif
1397
0
    xmlFree(elem);
1398
0
}
1399
1400
1401
/**
1402
 * xmlAddElementDecl:
1403
 * @ctxt:  the validation context
1404
 * @dtd:  pointer to the DTD
1405
 * @name:  the entity name
1406
 * @type:  the element type
1407
 * @content:  the element content tree or NULL
1408
 *
1409
 * Register a new element declaration
1410
 *
1411
 * Returns NULL if not, otherwise the entity
1412
 */
1413
xmlElementPtr
1414
xmlAddElementDecl(xmlValidCtxtPtr ctxt,
1415
                  xmlDtdPtr dtd, const xmlChar *name,
1416
                  xmlElementTypeVal type,
1417
0
      xmlElementContentPtr content) {
1418
0
    xmlElementPtr ret;
1419
0
    xmlElementTablePtr table;
1420
0
    xmlAttributePtr oldAttributes = NULL;
1421
0
    xmlChar *ns, *uqname;
1422
1423
0
    if (dtd == NULL) {
1424
0
  return(NULL);
1425
0
    }
1426
0
    if (name == NULL) {
1427
0
  return(NULL);
1428
0
    }
1429
1430
0
    switch (type) {
1431
0
        case XML_ELEMENT_TYPE_EMPTY:
1432
0
      if (content != NULL) {
1433
0
    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1434
0
            "xmlAddElementDecl: content != NULL for EMPTY\n",
1435
0
      NULL);
1436
0
    return(NULL);
1437
0
      }
1438
0
      break;
1439
0
  case XML_ELEMENT_TYPE_ANY:
1440
0
      if (content != NULL) {
1441
0
    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1442
0
            "xmlAddElementDecl: content != NULL for ANY\n",
1443
0
      NULL);
1444
0
    return(NULL);
1445
0
      }
1446
0
      break;
1447
0
  case XML_ELEMENT_TYPE_MIXED:
1448
0
      if (content == NULL) {
1449
0
    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1450
0
            "xmlAddElementDecl: content == NULL for MIXED\n",
1451
0
      NULL);
1452
0
    return(NULL);
1453
0
      }
1454
0
      break;
1455
0
  case XML_ELEMENT_TYPE_ELEMENT:
1456
0
      if (content == NULL) {
1457
0
    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1458
0
            "xmlAddElementDecl: content == NULL for ELEMENT\n",
1459
0
      NULL);
1460
0
    return(NULL);
1461
0
      }
1462
0
      break;
1463
0
  default:
1464
0
      xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1465
0
        "Internal: ELEMENT decl corrupted invalid type\n",
1466
0
        NULL);
1467
0
      return(NULL);
1468
0
    }
1469
1470
    /*
1471
     * check if name is a QName
1472
     */
1473
0
    uqname = xmlSplitQName2(name, &ns);
1474
0
    if (uqname != NULL)
1475
0
  name = uqname;
1476
1477
    /*
1478
     * Create the Element table if needed.
1479
     */
1480
0
    table = (xmlElementTablePtr) dtd->elements;
1481
0
    if (table == NULL) {
1482
0
  xmlDictPtr dict = NULL;
1483
1484
0
  if (dtd->doc != NULL)
1485
0
      dict = dtd->doc->dict;
1486
0
        table = xmlHashCreateDict(0, dict);
1487
0
  dtd->elements = (void *) table;
1488
0
    }
1489
0
    if (table == NULL) {
1490
0
  xmlVErrMemory(ctxt,
1491
0
            "xmlAddElementDecl: Table creation failed!\n");
1492
0
  if (uqname != NULL)
1493
0
      xmlFree(uqname);
1494
0
  if (ns != NULL)
1495
0
      xmlFree(ns);
1496
0
        return(NULL);
1497
0
    }
1498
1499
    /*
1500
     * lookup old attributes inserted on an undefined element in the
1501
     * internal subset.
1502
     */
1503
0
    if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1504
0
  ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1505
0
  if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1506
0
      oldAttributes = ret->attributes;
1507
0
      ret->attributes = NULL;
1508
0
      xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1509
0
      xmlFreeElement(ret);
1510
0
  }
1511
0
    }
1512
1513
    /*
1514
     * The element may already be present if one of its attribute
1515
     * was registered first
1516
     */
1517
0
    ret = xmlHashLookup2(table, name, ns);
1518
0
    if (ret != NULL) {
1519
0
  if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1520
0
#ifdef LIBXML_VALID_ENABLED
1521
      /*
1522
       * The element is already defined in this DTD.
1523
       */
1524
0
      xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1525
0
                      "Redefinition of element %s\n",
1526
0
          name, NULL, NULL);
1527
0
#endif /* LIBXML_VALID_ENABLED */
1528
0
      if (uqname != NULL)
1529
0
    xmlFree(uqname);
1530
0
            if (ns != NULL)
1531
0
          xmlFree(ns);
1532
0
      return(NULL);
1533
0
  }
1534
0
  if (ns != NULL) {
1535
0
      xmlFree(ns);
1536
0
      ns = NULL;
1537
0
  }
1538
0
    } else {
1539
0
  ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1540
0
  if (ret == NULL) {
1541
0
      xmlVErrMemory(ctxt, "malloc failed");
1542
0
      if (uqname != NULL)
1543
0
    xmlFree(uqname);
1544
0
            if (ns != NULL)
1545
0
          xmlFree(ns);
1546
0
      return(NULL);
1547
0
  }
1548
0
  memset(ret, 0, sizeof(xmlElement));
1549
0
  ret->type = XML_ELEMENT_DECL;
1550
1551
  /*
1552
   * fill the structure.
1553
   */
1554
0
  ret->name = xmlStrdup(name);
1555
0
  if (ret->name == NULL) {
1556
0
      xmlVErrMemory(ctxt, "malloc failed");
1557
0
      if (uqname != NULL)
1558
0
    xmlFree(uqname);
1559
0
            if (ns != NULL)
1560
0
          xmlFree(ns);
1561
0
      xmlFree(ret);
1562
0
      return(NULL);
1563
0
  }
1564
0
  ret->prefix = ns;
1565
1566
  /*
1567
   * Validity Check:
1568
   * Insertion must not fail
1569
   */
1570
0
  if (xmlHashAddEntry2(table, name, ns, ret)) {
1571
0
#ifdef LIBXML_VALID_ENABLED
1572
      /*
1573
       * The element is already defined in this DTD.
1574
       */
1575
0
      xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1576
0
                      "Redefinition of element %s\n",
1577
0
          name, NULL, NULL);
1578
0
#endif /* LIBXML_VALID_ENABLED */
1579
0
      xmlFreeElement(ret);
1580
0
      if (uqname != NULL)
1581
0
    xmlFree(uqname);
1582
0
      return(NULL);
1583
0
  }
1584
  /*
1585
   * For new element, may have attributes from earlier
1586
   * definition in internal subset
1587
   */
1588
0
  ret->attributes = oldAttributes;
1589
0
    }
1590
1591
    /*
1592
     * Finish to fill the structure.
1593
     */
1594
0
    ret->etype = type;
1595
    /*
1596
     * Avoid a stupid copy when called by the parser
1597
     * and flag it by setting a special parent value
1598
     * so the parser doesn't unallocate it.
1599
     */
1600
0
    if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) {
1601
0
  ret->content = content;
1602
0
  if (content != NULL)
1603
0
      content->parent = (xmlElementContentPtr) 1;
1604
0
    } else {
1605
0
  ret->content = xmlCopyDocElementContent(dtd->doc, content);
1606
0
    }
1607
1608
    /*
1609
     * Link it to the DTD
1610
     */
1611
0
    ret->parent = dtd;
1612
0
    ret->doc = dtd->doc;
1613
0
    if (dtd->last == NULL) {
1614
0
  dtd->children = dtd->last = (xmlNodePtr) ret;
1615
0
    } else {
1616
0
        dtd->last->next = (xmlNodePtr) ret;
1617
0
  ret->prev = dtd->last;
1618
0
  dtd->last = (xmlNodePtr) ret;
1619
0
    }
1620
0
    if (uqname != NULL)
1621
0
  xmlFree(uqname);
1622
0
    return(ret);
1623
0
}
1624
1625
static void
1626
0
xmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) {
1627
0
    xmlFreeElement((xmlElementPtr) elem);
1628
0
}
1629
1630
/**
1631
 * xmlFreeElementTable:
1632
 * @table:  An element table
1633
 *
1634
 * Deallocate the memory used by an element hash table.
1635
 */
1636
void
1637
0
xmlFreeElementTable(xmlElementTablePtr table) {
1638
0
    xmlHashFree(table, xmlFreeElementTableEntry);
1639
0
}
1640
1641
#ifdef LIBXML_TREE_ENABLED
1642
/**
1643
 * xmlCopyElement:
1644
 * @elem:  An element
1645
 *
1646
 * Build a copy of an element.
1647
 *
1648
 * Returns the new xmlElementPtr or NULL in case of error.
1649
 */
1650
static void *
1651
0
xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1652
0
    xmlElementPtr elem = (xmlElementPtr) payload;
1653
0
    xmlElementPtr cur;
1654
1655
0
    cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1656
0
    if (cur == NULL) {
1657
0
  xmlVErrMemory(NULL, "malloc failed");
1658
0
  return(NULL);
1659
0
    }
1660
0
    memset(cur, 0, sizeof(xmlElement));
1661
0
    cur->type = XML_ELEMENT_DECL;
1662
0
    cur->etype = elem->etype;
1663
0
    if (elem->name != NULL)
1664
0
  cur->name = xmlStrdup(elem->name);
1665
0
    else
1666
0
  cur->name = NULL;
1667
0
    if (elem->prefix != NULL)
1668
0
  cur->prefix = xmlStrdup(elem->prefix);
1669
0
    else
1670
0
  cur->prefix = NULL;
1671
0
    cur->content = xmlCopyElementContent(elem->content);
1672
    /* TODO : rebuild the attribute list on the copy */
1673
0
    cur->attributes = NULL;
1674
0
    return(cur);
1675
0
}
1676
1677
/**
1678
 * xmlCopyElementTable:
1679
 * @table:  An element table
1680
 *
1681
 * Build a copy of an element table.
1682
 *
1683
 * Returns the new xmlElementTablePtr or NULL in case of error.
1684
 */
1685
xmlElementTablePtr
1686
0
xmlCopyElementTable(xmlElementTablePtr table) {
1687
0
    return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1688
0
}
1689
#endif /* LIBXML_TREE_ENABLED */
1690
1691
#ifdef LIBXML_OUTPUT_ENABLED
1692
/**
1693
 * xmlDumpElementDecl:
1694
 * @buf:  the XML buffer output
1695
 * @elem:  An element table
1696
 *
1697
 * This will dump the content of the element declaration as an XML
1698
 * DTD definition
1699
 */
1700
void
1701
0
xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1702
0
    if ((buf == NULL) || (elem == NULL))
1703
0
        return;
1704
0
    switch (elem->etype) {
1705
0
  case XML_ELEMENT_TYPE_EMPTY:
1706
0
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1707
0
      if (elem->prefix != NULL) {
1708
0
    xmlBufferWriteCHAR(buf, elem->prefix);
1709
0
    xmlBufferWriteChar(buf, ":");
1710
0
      }
1711
0
      xmlBufferWriteCHAR(buf, elem->name);
1712
0
      xmlBufferWriteChar(buf, " EMPTY>\n");
1713
0
      break;
1714
0
  case XML_ELEMENT_TYPE_ANY:
1715
0
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1716
0
      if (elem->prefix != NULL) {
1717
0
    xmlBufferWriteCHAR(buf, elem->prefix);
1718
0
    xmlBufferWriteChar(buf, ":");
1719
0
      }
1720
0
      xmlBufferWriteCHAR(buf, elem->name);
1721
0
      xmlBufferWriteChar(buf, " ANY>\n");
1722
0
      break;
1723
0
  case XML_ELEMENT_TYPE_MIXED:
1724
0
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1725
0
      if (elem->prefix != NULL) {
1726
0
    xmlBufferWriteCHAR(buf, elem->prefix);
1727
0
    xmlBufferWriteChar(buf, ":");
1728
0
      }
1729
0
      xmlBufferWriteCHAR(buf, elem->name);
1730
0
      xmlBufferWriteChar(buf, " ");
1731
0
      xmlDumpElementContent(buf, elem->content);
1732
0
      xmlBufferWriteChar(buf, ">\n");
1733
0
      break;
1734
0
  case XML_ELEMENT_TYPE_ELEMENT:
1735
0
      xmlBufferWriteChar(buf, "<!ELEMENT ");
1736
0
      if (elem->prefix != NULL) {
1737
0
    xmlBufferWriteCHAR(buf, elem->prefix);
1738
0
    xmlBufferWriteChar(buf, ":");
1739
0
      }
1740
0
      xmlBufferWriteCHAR(buf, elem->name);
1741
0
      xmlBufferWriteChar(buf, " ");
1742
0
      xmlDumpElementContent(buf, elem->content);
1743
0
      xmlBufferWriteChar(buf, ">\n");
1744
0
      break;
1745
0
  default:
1746
0
      xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1747
0
        "Internal: ELEMENT struct corrupted invalid type\n",
1748
0
        NULL);
1749
0
    }
1750
0
}
1751
1752
/**
1753
 * xmlDumpElementDeclScan:
1754
 * @elem:  An element table
1755
 * @buf:  the XML buffer output
1756
 *
1757
 * This routine is used by the hash scan function.  It just reverses
1758
 * the arguments.
1759
 */
1760
static void
1761
xmlDumpElementDeclScan(void *elem, void *buf,
1762
0
                       const xmlChar *name ATTRIBUTE_UNUSED) {
1763
0
    xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1764
0
}
1765
1766
/**
1767
 * xmlDumpElementTable:
1768
 * @buf:  the XML buffer output
1769
 * @table:  An element table
1770
 *
1771
 * This will dump the content of the element table as an XML DTD definition
1772
 */
1773
void
1774
0
xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1775
0
    if ((buf == NULL) || (table == NULL))
1776
0
        return;
1777
0
    xmlHashScan(table, xmlDumpElementDeclScan, buf);
1778
0
}
1779
#endif /* LIBXML_OUTPUT_ENABLED */
1780
1781
/**
1782
 * xmlCreateEnumeration:
1783
 * @name:  the enumeration name or NULL
1784
 *
1785
 * create and initialize an enumeration attribute node.
1786
 *
1787
 * Returns the xmlEnumerationPtr just created or NULL in case
1788
 *                of error.
1789
 */
1790
xmlEnumerationPtr
1791
2.21k
xmlCreateEnumeration(const xmlChar *name) {
1792
2.21k
    xmlEnumerationPtr ret;
1793
1794
2.21k
    ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1795
2.21k
    if (ret == NULL) {
1796
0
  xmlVErrMemory(NULL, "malloc failed");
1797
0
        return(NULL);
1798
0
    }
1799
2.21k
    memset(ret, 0, sizeof(xmlEnumeration));
1800
1801
2.21k
    if (name != NULL)
1802
2.21k
        ret->name = xmlStrdup(name);
1803
2.21k
    return(ret);
1804
2.21k
}
1805
1806
/**
1807
 * xmlFreeEnumeration:
1808
 * @cur:  the tree to free.
1809
 *
1810
 * free an enumeration attribute node (recursive).
1811
 */
1812
void
1813
2.25k
xmlFreeEnumeration(xmlEnumerationPtr cur) {
1814
2.25k
    if (cur == NULL) return;
1815
1816
2.21k
    if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1817
1818
2.21k
    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1819
2.21k
    xmlFree(cur);
1820
2.21k
}
1821
1822
#ifdef LIBXML_TREE_ENABLED
1823
/**
1824
 * xmlCopyEnumeration:
1825
 * @cur:  the tree to copy.
1826
 *
1827
 * Copy an enumeration attribute node (recursive).
1828
 *
1829
 * Returns the xmlEnumerationPtr just created or NULL in case
1830
 *                of error.
1831
 */
1832
xmlEnumerationPtr
1833
0
xmlCopyEnumeration(xmlEnumerationPtr cur) {
1834
0
    xmlEnumerationPtr ret;
1835
1836
0
    if (cur == NULL) return(NULL);
1837
0
    ret = xmlCreateEnumeration((xmlChar *) cur->name);
1838
0
    if (ret == NULL) return(NULL);
1839
1840
0
    if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1841
0
    else ret->next = NULL;
1842
1843
0
    return(ret);
1844
0
}
1845
#endif /* LIBXML_TREE_ENABLED */
1846
1847
#ifdef LIBXML_OUTPUT_ENABLED
1848
/**
1849
 * xmlDumpEnumeration:
1850
 * @buf:  the XML buffer output
1851
 * @enum:  An enumeration
1852
 *
1853
 * This will dump the content of the enumeration
1854
 */
1855
static void
1856
0
xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1857
0
    if ((buf == NULL) || (cur == NULL))
1858
0
        return;
1859
1860
0
    xmlBufferWriteCHAR(buf, cur->name);
1861
0
    if (cur->next == NULL)
1862
0
  xmlBufferWriteChar(buf, ")");
1863
0
    else {
1864
0
  xmlBufferWriteChar(buf, " | ");
1865
0
  xmlDumpEnumeration(buf, cur->next);
1866
0
    }
1867
0
}
1868
#endif /* LIBXML_OUTPUT_ENABLED */
1869
1870
#ifdef LIBXML_VALID_ENABLED
1871
/**
1872
 * xmlScanIDAttributeDecl:
1873
 * @ctxt:  the validation context
1874
 * @elem:  the element name
1875
 * @err: whether to raise errors here
1876
 *
1877
 * Verify that the element don't have too many ID attributes
1878
 * declared.
1879
 *
1880
 * Returns the number of ID attributes found.
1881
 */
1882
static int
1883
0
xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1884
0
    xmlAttributePtr cur;
1885
0
    int ret = 0;
1886
1887
0
    if (elem == NULL) return(0);
1888
0
    cur = elem->attributes;
1889
0
    while (cur != NULL) {
1890
0
        if (cur->atype == XML_ATTRIBUTE_ID) {
1891
0
      ret ++;
1892
0
      if ((ret > 1) && (err))
1893
0
    xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1894
0
         "Element %s has too many ID attributes defined : %s\n",
1895
0
           elem->name, cur->name, NULL);
1896
0
  }
1897
0
  cur = cur->nexth;
1898
0
    }
1899
0
    return(ret);
1900
0
}
1901
#endif /* LIBXML_VALID_ENABLED */
1902
1903
/**
1904
 * xmlFreeAttribute:
1905
 * @elem:  An attribute
1906
 *
1907
 * Deallocate the memory used by an attribute definition
1908
 */
1909
static void
1910
0
xmlFreeAttribute(xmlAttributePtr attr) {
1911
0
    xmlDictPtr dict;
1912
1913
0
    if (attr == NULL) return;
1914
0
    if (attr->doc != NULL)
1915
0
  dict = attr->doc->dict;
1916
0
    else
1917
0
  dict = NULL;
1918
0
    xmlUnlinkNode((xmlNodePtr) attr);
1919
0
    if (attr->tree != NULL)
1920
0
        xmlFreeEnumeration(attr->tree);
1921
0
    if (dict) {
1922
0
        if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1923
0
      xmlFree((xmlChar *) attr->elem);
1924
0
        if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1925
0
      xmlFree((xmlChar *) attr->name);
1926
0
        if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1927
0
      xmlFree((xmlChar *) attr->prefix);
1928
0
        if ((attr->defaultValue != NULL) &&
1929
0
      (!xmlDictOwns(dict, attr->defaultValue)))
1930
0
      xmlFree((xmlChar *) attr->defaultValue);
1931
0
    } else {
1932
0
  if (attr->elem != NULL)
1933
0
      xmlFree((xmlChar *) attr->elem);
1934
0
  if (attr->name != NULL)
1935
0
      xmlFree((xmlChar *) attr->name);
1936
0
  if (attr->defaultValue != NULL)
1937
0
      xmlFree((xmlChar *) attr->defaultValue);
1938
0
  if (attr->prefix != NULL)
1939
0
      xmlFree((xmlChar *) attr->prefix);
1940
0
    }
1941
0
    xmlFree(attr);
1942
0
}
1943
1944
1945
/**
1946
 * xmlAddAttributeDecl:
1947
 * @ctxt:  the validation context
1948
 * @dtd:  pointer to the DTD
1949
 * @elem:  the element name
1950
 * @name:  the attribute name
1951
 * @ns:  the attribute namespace prefix
1952
 * @type:  the attribute type
1953
 * @def:  the attribute default type
1954
 * @defaultValue:  the attribute default value
1955
 * @tree:  if it's an enumeration, the associated list
1956
 *
1957
 * Register a new attribute declaration
1958
 * Note that @tree becomes the ownership of the DTD
1959
 *
1960
 * Returns NULL if not new, otherwise the attribute decl
1961
 */
1962
xmlAttributePtr
1963
xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
1964
                    xmlDtdPtr dtd, const xmlChar *elem,
1965
                    const xmlChar *name, const xmlChar *ns,
1966
        xmlAttributeType type, xmlAttributeDefault def,
1967
0
        const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1968
0
    xmlAttributePtr ret;
1969
0
    xmlAttributeTablePtr table;
1970
0
    xmlElementPtr elemDef;
1971
0
    xmlDictPtr dict = NULL;
1972
1973
0
    if (dtd == NULL) {
1974
0
  xmlFreeEnumeration(tree);
1975
0
  return(NULL);
1976
0
    }
1977
0
    if (name == NULL) {
1978
0
  xmlFreeEnumeration(tree);
1979
0
  return(NULL);
1980
0
    }
1981
0
    if (elem == NULL) {
1982
0
  xmlFreeEnumeration(tree);
1983
0
  return(NULL);
1984
0
    }
1985
0
    if (dtd->doc != NULL)
1986
0
  dict = dtd->doc->dict;
1987
1988
0
#ifdef LIBXML_VALID_ENABLED
1989
    /*
1990
     * Check the type and possibly the default value.
1991
     */
1992
0
    switch (type) {
1993
0
        case XML_ATTRIBUTE_CDATA:
1994
0
      break;
1995
0
        case XML_ATTRIBUTE_ID:
1996
0
      break;
1997
0
        case XML_ATTRIBUTE_IDREF:
1998
0
      break;
1999
0
        case XML_ATTRIBUTE_IDREFS:
2000
0
      break;
2001
0
        case XML_ATTRIBUTE_ENTITY:
2002
0
      break;
2003
0
        case XML_ATTRIBUTE_ENTITIES:
2004
0
      break;
2005
0
        case XML_ATTRIBUTE_NMTOKEN:
2006
0
      break;
2007
0
        case XML_ATTRIBUTE_NMTOKENS:
2008
0
      break;
2009
0
        case XML_ATTRIBUTE_ENUMERATION:
2010
0
      break;
2011
0
        case XML_ATTRIBUTE_NOTATION:
2012
0
      break;
2013
0
  default:
2014
0
      xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2015
0
        "Internal: ATTRIBUTE struct corrupted invalid type\n",
2016
0
        NULL);
2017
0
      xmlFreeEnumeration(tree);
2018
0
      return(NULL);
2019
0
    }
2020
0
    if ((defaultValue != NULL) &&
2021
0
        (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
2022
0
  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2023
0
                  "Attribute %s of %s: invalid default value\n",
2024
0
                  elem, name, defaultValue);
2025
0
  defaultValue = NULL;
2026
0
  if (ctxt != NULL)
2027
0
      ctxt->valid = 0;
2028
0
    }
2029
0
#endif /* LIBXML_VALID_ENABLED */
2030
2031
    /*
2032
     * Check first that an attribute defined in the external subset wasn't
2033
     * already defined in the internal subset
2034
     */
2035
0
    if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2036
0
  (dtd->doc->intSubset != NULL) &&
2037
0
  (dtd->doc->intSubset->attributes != NULL)) {
2038
0
        ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2039
0
  if (ret != NULL) {
2040
0
      xmlFreeEnumeration(tree);
2041
0
      return(NULL);
2042
0
  }
2043
0
    }
2044
2045
    /*
2046
     * Create the Attribute table if needed.
2047
     */
2048
0
    table = (xmlAttributeTablePtr) dtd->attributes;
2049
0
    if (table == NULL) {
2050
0
        table = xmlHashCreateDict(0, dict);
2051
0
  dtd->attributes = (void *) table;
2052
0
    }
2053
0
    if (table == NULL) {
2054
0
  xmlVErrMemory(ctxt,
2055
0
            "xmlAddAttributeDecl: Table creation failed!\n");
2056
0
  xmlFreeEnumeration(tree);
2057
0
        return(NULL);
2058
0
    }
2059
2060
2061
0
    ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2062
0
    if (ret == NULL) {
2063
0
  xmlVErrMemory(ctxt, "malloc failed");
2064
0
  xmlFreeEnumeration(tree);
2065
0
  return(NULL);
2066
0
    }
2067
0
    memset(ret, 0, sizeof(xmlAttribute));
2068
0
    ret->type = XML_ATTRIBUTE_DECL;
2069
2070
    /*
2071
     * fill the structure.
2072
     */
2073
0
    ret->atype = type;
2074
    /*
2075
     * doc must be set before possible error causes call
2076
     * to xmlFreeAttribute (because it's used to check on
2077
     * dict use)
2078
     */
2079
0
    ret->doc = dtd->doc;
2080
0
    if (dict) {
2081
0
  ret->name = xmlDictLookup(dict, name, -1);
2082
0
  ret->prefix = xmlDictLookup(dict, ns, -1);
2083
0
  ret->elem = xmlDictLookup(dict, elem, -1);
2084
0
    } else {
2085
0
  ret->name = xmlStrdup(name);
2086
0
  ret->prefix = xmlStrdup(ns);
2087
0
  ret->elem = xmlStrdup(elem);
2088
0
    }
2089
0
    ret->def = def;
2090
0
    ret->tree = tree;
2091
0
    if (defaultValue != NULL) {
2092
0
        if (dict)
2093
0
      ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2094
0
  else
2095
0
      ret->defaultValue = xmlStrdup(defaultValue);
2096
0
    }
2097
2098
    /*
2099
     * Validity Check:
2100
     * Search the DTD for previous declarations of the ATTLIST
2101
     */
2102
0
    if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2103
0
#ifdef LIBXML_VALID_ENABLED
2104
  /*
2105
   * The attribute is already defined in this DTD.
2106
   */
2107
0
  xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2108
0
     "Attribute %s of element %s: already defined\n",
2109
0
     name, elem, NULL);
2110
0
#endif /* LIBXML_VALID_ENABLED */
2111
0
  xmlFreeAttribute(ret);
2112
0
  return(NULL);
2113
0
    }
2114
2115
    /*
2116
     * Validity Check:
2117
     * Multiple ID per element
2118
     */
2119
0
    elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem, 1);
2120
0
    if (elemDef != NULL) {
2121
2122
0
#ifdef LIBXML_VALID_ENABLED
2123
0
        if ((type == XML_ATTRIBUTE_ID) &&
2124
0
      (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2125
0
      xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2126
0
     "Element %s has too may ID attributes defined : %s\n",
2127
0
       elem, name, NULL);
2128
0
      if (ctxt != NULL)
2129
0
    ctxt->valid = 0;
2130
0
  }
2131
0
#endif /* LIBXML_VALID_ENABLED */
2132
2133
  /*
2134
   * Insert namespace default def first they need to be
2135
   * processed first.
2136
   */
2137
0
  if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2138
0
      ((ret->prefix != NULL &&
2139
0
       (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2140
0
      ret->nexth = elemDef->attributes;
2141
0
      elemDef->attributes = ret;
2142
0
  } else {
2143
0
      xmlAttributePtr tmp = elemDef->attributes;
2144
2145
0
      while ((tmp != NULL) &&
2146
0
       ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2147
0
        ((ret->prefix != NULL &&
2148
0
         (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2149
0
    if (tmp->nexth == NULL)
2150
0
        break;
2151
0
    tmp = tmp->nexth;
2152
0
      }
2153
0
      if (tmp != NULL) {
2154
0
    ret->nexth = tmp->nexth;
2155
0
          tmp->nexth = ret;
2156
0
      } else {
2157
0
    ret->nexth = elemDef->attributes;
2158
0
    elemDef->attributes = ret;
2159
0
      }
2160
0
  }
2161
0
    }
2162
2163
    /*
2164
     * Link it to the DTD
2165
     */
2166
0
    ret->parent = dtd;
2167
0
    if (dtd->last == NULL) {
2168
0
  dtd->children = dtd->last = (xmlNodePtr) ret;
2169
0
    } else {
2170
0
        dtd->last->next = (xmlNodePtr) ret;
2171
0
  ret->prev = dtd->last;
2172
0
  dtd->last = (xmlNodePtr) ret;
2173
0
    }
2174
0
    return(ret);
2175
0
}
2176
2177
static void
2178
0
xmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) {
2179
0
    xmlFreeAttribute((xmlAttributePtr) attr);
2180
0
}
2181
2182
/**
2183
 * xmlFreeAttributeTable:
2184
 * @table:  An attribute table
2185
 *
2186
 * Deallocate the memory used by an entities hash table.
2187
 */
2188
void
2189
0
xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2190
0
    xmlHashFree(table, xmlFreeAttributeTableEntry);
2191
0
}
2192
2193
#ifdef LIBXML_TREE_ENABLED
2194
/**
2195
 * xmlCopyAttribute:
2196
 * @attr:  An attribute
2197
 *
2198
 * Build a copy of an attribute.
2199
 *
2200
 * Returns the new xmlAttributePtr or NULL in case of error.
2201
 */
2202
static void *
2203
0
xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2204
0
    xmlAttributePtr attr = (xmlAttributePtr) payload;
2205
0
    xmlAttributePtr cur;
2206
2207
0
    cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2208
0
    if (cur == NULL) {
2209
0
  xmlVErrMemory(NULL, "malloc failed");
2210
0
  return(NULL);
2211
0
    }
2212
0
    memset(cur, 0, sizeof(xmlAttribute));
2213
0
    cur->type = XML_ATTRIBUTE_DECL;
2214
0
    cur->atype = attr->atype;
2215
0
    cur->def = attr->def;
2216
0
    cur->tree = xmlCopyEnumeration(attr->tree);
2217
0
    if (attr->elem != NULL)
2218
0
  cur->elem = xmlStrdup(attr->elem);
2219
0
    if (attr->name != NULL)
2220
0
  cur->name = xmlStrdup(attr->name);
2221
0
    if (attr->prefix != NULL)
2222
0
  cur->prefix = xmlStrdup(attr->prefix);
2223
0
    if (attr->defaultValue != NULL)
2224
0
  cur->defaultValue = xmlStrdup(attr->defaultValue);
2225
0
    return(cur);
2226
0
}
2227
2228
/**
2229
 * xmlCopyAttributeTable:
2230
 * @table:  An attribute table
2231
 *
2232
 * Build a copy of an attribute table.
2233
 *
2234
 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2235
 */
2236
xmlAttributeTablePtr
2237
0
xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2238
0
    return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2239
0
}
2240
#endif /* LIBXML_TREE_ENABLED */
2241
2242
#ifdef LIBXML_OUTPUT_ENABLED
2243
/**
2244
 * xmlDumpAttributeDecl:
2245
 * @buf:  the XML buffer output
2246
 * @attr:  An attribute declaration
2247
 *
2248
 * This will dump the content of the attribute declaration as an XML
2249
 * DTD definition
2250
 */
2251
void
2252
0
xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2253
0
    if ((buf == NULL) || (attr == NULL))
2254
0
        return;
2255
0
    xmlBufferWriteChar(buf, "<!ATTLIST ");
2256
0
    xmlBufferWriteCHAR(buf, attr->elem);
2257
0
    xmlBufferWriteChar(buf, " ");
2258
0
    if (attr->prefix != NULL) {
2259
0
  xmlBufferWriteCHAR(buf, attr->prefix);
2260
0
  xmlBufferWriteChar(buf, ":");
2261
0
    }
2262
0
    xmlBufferWriteCHAR(buf, attr->name);
2263
0
    switch (attr->atype) {
2264
0
  case XML_ATTRIBUTE_CDATA:
2265
0
      xmlBufferWriteChar(buf, " CDATA");
2266
0
      break;
2267
0
  case XML_ATTRIBUTE_ID:
2268
0
      xmlBufferWriteChar(buf, " ID");
2269
0
      break;
2270
0
  case XML_ATTRIBUTE_IDREF:
2271
0
      xmlBufferWriteChar(buf, " IDREF");
2272
0
      break;
2273
0
  case XML_ATTRIBUTE_IDREFS:
2274
0
      xmlBufferWriteChar(buf, " IDREFS");
2275
0
      break;
2276
0
  case XML_ATTRIBUTE_ENTITY:
2277
0
      xmlBufferWriteChar(buf, " ENTITY");
2278
0
      break;
2279
0
  case XML_ATTRIBUTE_ENTITIES:
2280
0
      xmlBufferWriteChar(buf, " ENTITIES");
2281
0
      break;
2282
0
  case XML_ATTRIBUTE_NMTOKEN:
2283
0
      xmlBufferWriteChar(buf, " NMTOKEN");
2284
0
      break;
2285
0
  case XML_ATTRIBUTE_NMTOKENS:
2286
0
      xmlBufferWriteChar(buf, " NMTOKENS");
2287
0
      break;
2288
0
  case XML_ATTRIBUTE_ENUMERATION:
2289
0
      xmlBufferWriteChar(buf, " (");
2290
0
      xmlDumpEnumeration(buf, attr->tree);
2291
0
      break;
2292
0
  case XML_ATTRIBUTE_NOTATION:
2293
0
      xmlBufferWriteChar(buf, " NOTATION (");
2294
0
      xmlDumpEnumeration(buf, attr->tree);
2295
0
      break;
2296
0
  default:
2297
0
      xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2298
0
        "Internal: ATTRIBUTE struct corrupted invalid type\n",
2299
0
        NULL);
2300
0
    }
2301
0
    switch (attr->def) {
2302
0
  case XML_ATTRIBUTE_NONE:
2303
0
      break;
2304
0
  case XML_ATTRIBUTE_REQUIRED:
2305
0
      xmlBufferWriteChar(buf, " #REQUIRED");
2306
0
      break;
2307
0
  case XML_ATTRIBUTE_IMPLIED:
2308
0
      xmlBufferWriteChar(buf, " #IMPLIED");
2309
0
      break;
2310
0
  case XML_ATTRIBUTE_FIXED:
2311
0
      xmlBufferWriteChar(buf, " #FIXED");
2312
0
      break;
2313
0
  default:
2314
0
      xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2315
0
        "Internal: ATTRIBUTE struct corrupted invalid def\n",
2316
0
        NULL);
2317
0
    }
2318
0
    if (attr->defaultValue != NULL) {
2319
0
  xmlBufferWriteChar(buf, " ");
2320
0
  xmlBufferWriteQuotedString(buf, attr->defaultValue);
2321
0
    }
2322
0
    xmlBufferWriteChar(buf, ">\n");
2323
0
}
2324
2325
/**
2326
 * xmlDumpAttributeDeclScan:
2327
 * @attr:  An attribute declaration
2328
 * @buf:  the XML buffer output
2329
 *
2330
 * This is used with the hash scan function - just reverses arguments
2331
 */
2332
static void
2333
xmlDumpAttributeDeclScan(void *attr, void *buf,
2334
0
                         const xmlChar *name ATTRIBUTE_UNUSED) {
2335
0
    xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2336
0
}
2337
2338
/**
2339
 * xmlDumpAttributeTable:
2340
 * @buf:  the XML buffer output
2341
 * @table:  An attribute table
2342
 *
2343
 * This will dump the content of the attribute table as an XML DTD definition
2344
 */
2345
void
2346
0
xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2347
0
    if ((buf == NULL) || (table == NULL))
2348
0
        return;
2349
0
    xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
2350
0
}
2351
#endif /* LIBXML_OUTPUT_ENABLED */
2352
2353
/************************************************************************
2354
 *                  *
2355
 *        NOTATIONs       *
2356
 *                  *
2357
 ************************************************************************/
2358
/**
2359
 * xmlFreeNotation:
2360
 * @not:  A notation
2361
 *
2362
 * Deallocate the memory used by an notation definition
2363
 */
2364
static void
2365
0
xmlFreeNotation(xmlNotationPtr nota) {
2366
0
    if (nota == NULL) return;
2367
0
    if (nota->name != NULL)
2368
0
  xmlFree((xmlChar *) nota->name);
2369
0
    if (nota->PublicID != NULL)
2370
0
  xmlFree((xmlChar *) nota->PublicID);
2371
0
    if (nota->SystemID != NULL)
2372
0
  xmlFree((xmlChar *) nota->SystemID);
2373
0
    xmlFree(nota);
2374
0
}
2375
2376
2377
/**
2378
 * xmlAddNotationDecl:
2379
 * @dtd:  pointer to the DTD
2380
 * @ctxt:  the validation context
2381
 * @name:  the entity name
2382
 * @PublicID:  the public identifier or NULL
2383
 * @SystemID:  the system identifier or NULL
2384
 *
2385
 * Register a new notation declaration
2386
 *
2387
 * Returns NULL if not, otherwise the entity
2388
 */
2389
xmlNotationPtr
2390
xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
2391
             const xmlChar *name,
2392
0
                   const xmlChar *PublicID, const xmlChar *SystemID) {
2393
0
    xmlNotationPtr ret;
2394
0
    xmlNotationTablePtr table;
2395
2396
0
    if (dtd == NULL) {
2397
0
  return(NULL);
2398
0
    }
2399
0
    if (name == NULL) {
2400
0
  return(NULL);
2401
0
    }
2402
0
    if ((PublicID == NULL) && (SystemID == NULL)) {
2403
0
  return(NULL);
2404
0
    }
2405
2406
    /*
2407
     * Create the Notation table if needed.
2408
     */
2409
0
    table = (xmlNotationTablePtr) dtd->notations;
2410
0
    if (table == NULL) {
2411
0
  xmlDictPtr dict = NULL;
2412
0
  if (dtd->doc != NULL)
2413
0
      dict = dtd->doc->dict;
2414
2415
0
        dtd->notations = table = xmlHashCreateDict(0, dict);
2416
0
    }
2417
0
    if (table == NULL) {
2418
0
  xmlVErrMemory(ctxt,
2419
0
    "xmlAddNotationDecl: Table creation failed!\n");
2420
0
        return(NULL);
2421
0
    }
2422
2423
0
    ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2424
0
    if (ret == NULL) {
2425
0
  xmlVErrMemory(ctxt, "malloc failed");
2426
0
  return(NULL);
2427
0
    }
2428
0
    memset(ret, 0, sizeof(xmlNotation));
2429
2430
    /*
2431
     * fill the structure.
2432
     */
2433
0
    ret->name = xmlStrdup(name);
2434
0
    if (SystemID != NULL)
2435
0
        ret->SystemID = xmlStrdup(SystemID);
2436
0
    if (PublicID != NULL)
2437
0
        ret->PublicID = xmlStrdup(PublicID);
2438
2439
    /*
2440
     * Validity Check:
2441
     * Check the DTD for previous declarations of the ATTLIST
2442
     */
2443
0
    if (xmlHashAddEntry(table, name, ret)) {
2444
0
#ifdef LIBXML_VALID_ENABLED
2445
0
  xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2446
0
        "xmlAddNotationDecl: %s already defined\n",
2447
0
        (const char *) name);
2448
0
#endif /* LIBXML_VALID_ENABLED */
2449
0
  xmlFreeNotation(ret);
2450
0
  return(NULL);
2451
0
    }
2452
0
    return(ret);
2453
0
}
2454
2455
static void
2456
0
xmlFreeNotationTableEntry(void *nota, const xmlChar *name ATTRIBUTE_UNUSED) {
2457
0
    xmlFreeNotation((xmlNotationPtr) nota);
2458
0
}
2459
2460
/**
2461
 * xmlFreeNotationTable:
2462
 * @table:  An notation table
2463
 *
2464
 * Deallocate the memory used by an entities hash table.
2465
 */
2466
void
2467
0
xmlFreeNotationTable(xmlNotationTablePtr table) {
2468
0
    xmlHashFree(table, xmlFreeNotationTableEntry);
2469
0
}
2470
2471
#ifdef LIBXML_TREE_ENABLED
2472
/**
2473
 * xmlCopyNotation:
2474
 * @nota:  A notation
2475
 *
2476
 * Build a copy of a notation.
2477
 *
2478
 * Returns the new xmlNotationPtr or NULL in case of error.
2479
 */
2480
static void *
2481
0
xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2482
0
    xmlNotationPtr nota = (xmlNotationPtr) payload;
2483
0
    xmlNotationPtr cur;
2484
2485
0
    cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2486
0
    if (cur == NULL) {
2487
0
  xmlVErrMemory(NULL, "malloc failed");
2488
0
  return(NULL);
2489
0
    }
2490
0
    if (nota->name != NULL)
2491
0
  cur->name = xmlStrdup(nota->name);
2492
0
    else
2493
0
  cur->name = NULL;
2494
0
    if (nota->PublicID != NULL)
2495
0
  cur->PublicID = xmlStrdup(nota->PublicID);
2496
0
    else
2497
0
  cur->PublicID = NULL;
2498
0
    if (nota->SystemID != NULL)
2499
0
  cur->SystemID = xmlStrdup(nota->SystemID);
2500
0
    else
2501
0
  cur->SystemID = NULL;
2502
0
    return(cur);
2503
0
}
2504
2505
/**
2506
 * xmlCopyNotationTable:
2507
 * @table:  A notation table
2508
 *
2509
 * Build a copy of a notation table.
2510
 *
2511
 * Returns the new xmlNotationTablePtr or NULL in case of error.
2512
 */
2513
xmlNotationTablePtr
2514
0
xmlCopyNotationTable(xmlNotationTablePtr table) {
2515
0
    return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2516
0
}
2517
#endif /* LIBXML_TREE_ENABLED */
2518
2519
#ifdef LIBXML_OUTPUT_ENABLED
2520
/**
2521
 * xmlDumpNotationDecl:
2522
 * @buf:  the XML buffer output
2523
 * @nota:  A notation declaration
2524
 *
2525
 * This will dump the content the notation declaration as an XML DTD definition
2526
 */
2527
void
2528
0
xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2529
0
    if ((buf == NULL) || (nota == NULL))
2530
0
        return;
2531
0
    xmlBufferWriteChar(buf, "<!NOTATION ");
2532
0
    xmlBufferWriteCHAR(buf, nota->name);
2533
0
    if (nota->PublicID != NULL) {
2534
0
  xmlBufferWriteChar(buf, " PUBLIC ");
2535
0
  xmlBufferWriteQuotedString(buf, nota->PublicID);
2536
0
  if (nota->SystemID != NULL) {
2537
0
      xmlBufferWriteChar(buf, " ");
2538
0
      xmlBufferWriteQuotedString(buf, nota->SystemID);
2539
0
  }
2540
0
    } else {
2541
0
  xmlBufferWriteChar(buf, " SYSTEM ");
2542
0
  xmlBufferWriteQuotedString(buf, nota->SystemID);
2543
0
    }
2544
0
    xmlBufferWriteChar(buf, " >\n");
2545
0
}
2546
2547
/**
2548
 * xmlDumpNotationDeclScan:
2549
 * @nota:  A notation declaration
2550
 * @buf:  the XML buffer output
2551
 *
2552
 * This is called with the hash scan function, and just reverses args
2553
 */
2554
static void
2555
xmlDumpNotationDeclScan(void *nota, void *buf,
2556
0
                        const xmlChar *name ATTRIBUTE_UNUSED) {
2557
0
    xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2558
0
}
2559
2560
/**
2561
 * xmlDumpNotationTable:
2562
 * @buf:  the XML buffer output
2563
 * @table:  A notation table
2564
 *
2565
 * This will dump the content of the notation table as an XML DTD definition
2566
 */
2567
void
2568
0
xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2569
0
    if ((buf == NULL) || (table == NULL))
2570
0
        return;
2571
0
    xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2572
0
}
2573
#endif /* LIBXML_OUTPUT_ENABLED */
2574
2575
/************************************************************************
2576
 *                  *
2577
 *        IDs         *
2578
 *                  *
2579
 ************************************************************************/
2580
/**
2581
 * DICT_FREE:
2582
 * @str:  a string
2583
 *
2584
 * Free a string if it is not owned by the "dict" dictionary in the
2585
 * current scope
2586
 */
2587
#define DICT_FREE(str)            \
2588
0
  if ((str) && ((!dict) ||       \
2589
0
      (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))  \
2590
0
      xmlFree((char *)(str));
2591
2592
/**
2593
 * xmlValidNormalizeString:
2594
 * @str: a string
2595
 *
2596
 * Normalize a string in-place.
2597
 */
2598
static void
2599
0
xmlValidNormalizeString(xmlChar *str) {
2600
0
    xmlChar *dst;
2601
0
    const xmlChar *src;
2602
2603
0
    if (str == NULL)
2604
0
        return;
2605
0
    src = str;
2606
0
    dst = str;
2607
2608
0
    while (*src == 0x20) src++;
2609
0
    while (*src != 0) {
2610
0
  if (*src == 0x20) {
2611
0
      while (*src == 0x20) src++;
2612
0
      if (*src != 0)
2613
0
    *dst++ = 0x20;
2614
0
  } else {
2615
0
      *dst++ = *src++;
2616
0
  }
2617
0
    }
2618
0
    *dst = 0;
2619
0
}
2620
2621
static int
2622
0
xmlIsStreaming(xmlValidCtxtPtr ctxt) {
2623
0
    xmlParserCtxtPtr pctxt;
2624
2625
0
    if (ctxt == NULL)
2626
0
        return(0);
2627
0
    if ((ctxt->flags & XML_VCTXT_USE_PCTXT) == 0)
2628
0
        return(0);
2629
0
    pctxt = ctxt->userData;
2630
0
    return(pctxt->parseMode == XML_PARSE_READER);
2631
0
}
2632
2633
/**
2634
 * xmlFreeID:
2635
 * @not:  A id
2636
 *
2637
 * Deallocate the memory used by an id definition
2638
 */
2639
static void
2640
0
xmlFreeID(xmlIDPtr id) {
2641
0
    xmlDictPtr dict = NULL;
2642
2643
0
    if (id == NULL) return;
2644
2645
0
    if (id->doc != NULL)
2646
0
        dict = id->doc->dict;
2647
2648
0
    if (id->value != NULL)
2649
0
  DICT_FREE(id->value)
2650
0
    if (id->name != NULL)
2651
0
  DICT_FREE(id->name)
2652
0
    xmlFree(id);
2653
0
}
2654
2655
2656
/**
2657
 * xmlAddID:
2658
 * @ctxt:  the validation context
2659
 * @doc:  pointer to the document
2660
 * @value:  the value name
2661
 * @attr:  the attribute holding the ID
2662
 *
2663
 * Register a new id declaration
2664
 *
2665
 * Returns NULL if not, otherwise the new xmlIDPtr
2666
 */
2667
xmlIDPtr
2668
xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2669
0
         xmlAttrPtr attr) {
2670
0
    xmlIDPtr ret;
2671
0
    xmlIDTablePtr table;
2672
2673
0
    if (doc == NULL) {
2674
0
  return(NULL);
2675
0
    }
2676
0
    if ((value == NULL) || (value[0] == 0)) {
2677
0
  return(NULL);
2678
0
    }
2679
0
    if (attr == NULL) {
2680
0
  return(NULL);
2681
0
    }
2682
2683
    /*
2684
     * Create the ID table if needed.
2685
     */
2686
0
    table = (xmlIDTablePtr) doc->ids;
2687
0
    if (table == NULL)  {
2688
0
        doc->ids = table = xmlHashCreateDict(0, doc->dict);
2689
0
    }
2690
0
    if (table == NULL) {
2691
0
  xmlVErrMemory(ctxt,
2692
0
    "xmlAddID: Table creation failed!\n");
2693
0
        return(NULL);
2694
0
    }
2695
2696
0
    ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2697
0
    if (ret == NULL) {
2698
0
  xmlVErrMemory(ctxt, "malloc failed");
2699
0
  return(NULL);
2700
0
    }
2701
2702
    /*
2703
     * fill the structure.
2704
     */
2705
0
    ret->value = xmlStrdup(value);
2706
0
    ret->doc = doc;
2707
0
    if (xmlIsStreaming(ctxt)) {
2708
  /*
2709
   * Operating in streaming mode, attr is gonna disappear
2710
   */
2711
0
  if (doc->dict != NULL)
2712
0
      ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2713
0
  else
2714
0
      ret->name = xmlStrdup(attr->name);
2715
0
  ret->attr = NULL;
2716
0
    } else {
2717
0
  ret->attr = attr;
2718
0
  ret->name = NULL;
2719
0
    }
2720
0
    ret->lineno = xmlGetLineNo(attr->parent);
2721
2722
0
    if (xmlHashAddEntry(table, value, ret) < 0) {
2723
0
#ifdef LIBXML_VALID_ENABLED
2724
  /*
2725
   * The id is already defined in this DTD.
2726
   */
2727
0
  if (ctxt != NULL) {
2728
0
      xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2729
0
          "ID %s already defined\n", value, NULL, NULL);
2730
0
  }
2731
0
#endif /* LIBXML_VALID_ENABLED */
2732
0
  xmlFreeID(ret);
2733
0
  return(NULL);
2734
0
    }
2735
0
    if (attr != NULL)
2736
0
  attr->atype = XML_ATTRIBUTE_ID;
2737
0
    return(ret);
2738
0
}
2739
2740
static void
2741
0
xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) {
2742
0
    xmlFreeID((xmlIDPtr) id);
2743
0
}
2744
2745
/**
2746
 * xmlFreeIDTable:
2747
 * @table:  An id table
2748
 *
2749
 * Deallocate the memory used by an ID hash table.
2750
 */
2751
void
2752
0
xmlFreeIDTable(xmlIDTablePtr table) {
2753
0
    xmlHashFree(table, xmlFreeIDTableEntry);
2754
0
}
2755
2756
/**
2757
 * xmlIsID:
2758
 * @doc:  the document
2759
 * @elem:  the element carrying the attribute
2760
 * @attr:  the attribute
2761
 *
2762
 * Determine whether an attribute is of type ID. In case we have DTD(s)
2763
 * then this is done if DTD loading has been requested. In the case
2764
 * of HTML documents parsed with the HTML parser, then ID detection is
2765
 * done systematically.
2766
 *
2767
 * Returns 0 or 1 depending on the lookup result
2768
 */
2769
int
2770
0
xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2771
0
    if ((attr == NULL) || (attr->name == NULL)) return(0);
2772
0
    if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2773
0
        (!strcmp((char *) attr->name, "id")) &&
2774
0
        (!strcmp((char *) attr->ns->prefix, "xml")))
2775
0
  return(1);
2776
0
    if (doc == NULL) return(0);
2777
0
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2778
0
        (doc->type != XML_HTML_DOCUMENT_NODE)) {
2779
0
  return(0);
2780
0
    } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2781
0
        if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2782
0
      ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2783
0
      ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2784
0
      return(1);
2785
0
  return(0);
2786
0
    } else if (elem == NULL) {
2787
0
  return(0);
2788
0
    } else {
2789
0
  xmlAttributePtr attrDecl = NULL;
2790
2791
0
  xmlChar felem[50], fattr[50];
2792
0
  xmlChar *fullelemname, *fullattrname;
2793
2794
0
  fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2795
0
      xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2796
0
      (xmlChar *)elem->name;
2797
2798
0
  fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2799
0
      xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2800
0
      (xmlChar *)attr->name;
2801
2802
0
  if (fullelemname != NULL && fullattrname != NULL) {
2803
0
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2804
0
                             fullattrname);
2805
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
2806
0
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2807
0
               fullattrname);
2808
0
  }
2809
2810
0
  if ((fullattrname != fattr) && (fullattrname != attr->name))
2811
0
      xmlFree(fullattrname);
2812
0
  if ((fullelemname != felem) && (fullelemname != elem->name))
2813
0
      xmlFree(fullelemname);
2814
2815
0
        if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2816
0
      return(1);
2817
0
    }
2818
0
    return(0);
2819
0
}
2820
2821
/**
2822
 * xmlRemoveID:
2823
 * @doc:  the document
2824
 * @attr:  the attribute
2825
 *
2826
 * Remove the given attribute from the ID table maintained internally.
2827
 *
2828
 * Returns -1 if the lookup failed and 0 otherwise
2829
 */
2830
int
2831
0
xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2832
0
    xmlIDTablePtr table;
2833
0
    xmlIDPtr id;
2834
0
    xmlChar *ID;
2835
2836
0
    if (doc == NULL) return(-1);
2837
0
    if (attr == NULL) return(-1);
2838
2839
0
    table = (xmlIDTablePtr) doc->ids;
2840
0
    if (table == NULL)
2841
0
        return(-1);
2842
2843
0
    ID = xmlNodeListGetString(doc, attr->children, 1);
2844
0
    if (ID == NULL)
2845
0
        return(-1);
2846
0
    xmlValidNormalizeString(ID);
2847
2848
0
    id = xmlHashLookup(table, ID);
2849
0
    if (id == NULL || id->attr != attr) {
2850
0
        xmlFree(ID);
2851
0
        return(-1);
2852
0
    }
2853
2854
0
    xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry);
2855
0
    xmlFree(ID);
2856
0
    attr->atype = 0;
2857
0
    return(0);
2858
0
}
2859
2860
/**
2861
 * xmlGetID:
2862
 * @doc:  pointer to the document
2863
 * @ID:  the ID value
2864
 *
2865
 * Search the attribute declaring the given ID
2866
 *
2867
 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2868
 */
2869
xmlAttrPtr
2870
0
xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2871
0
    xmlIDTablePtr table;
2872
0
    xmlIDPtr id;
2873
2874
0
    if (doc == NULL) {
2875
0
  return(NULL);
2876
0
    }
2877
2878
0
    if (ID == NULL) {
2879
0
  return(NULL);
2880
0
    }
2881
2882
0
    table = (xmlIDTablePtr) doc->ids;
2883
0
    if (table == NULL)
2884
0
        return(NULL);
2885
2886
0
    id = xmlHashLookup(table, ID);
2887
0
    if (id == NULL)
2888
0
  return(NULL);
2889
0
    if (id->attr == NULL) {
2890
  /*
2891
   * We are operating on a stream, return a well known reference
2892
   * since the attribute node doesn't exist anymore
2893
   */
2894
0
  return((xmlAttrPtr) doc);
2895
0
    }
2896
0
    return(id->attr);
2897
0
}
2898
2899
/************************************************************************
2900
 *                  *
2901
 *        Refs          *
2902
 *                  *
2903
 ************************************************************************/
2904
typedef struct xmlRemoveMemo_t
2905
{
2906
  xmlListPtr l;
2907
  xmlAttrPtr ap;
2908
} xmlRemoveMemo;
2909
2910
typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2911
2912
typedef struct xmlValidateMemo_t
2913
{
2914
    xmlValidCtxtPtr ctxt;
2915
    const xmlChar *name;
2916
} xmlValidateMemo;
2917
2918
typedef xmlValidateMemo *xmlValidateMemoPtr;
2919
2920
/**
2921
 * xmlFreeRef:
2922
 * @lk:  A list link
2923
 *
2924
 * Deallocate the memory used by a ref definition
2925
 */
2926
static void
2927
0
xmlFreeRef(xmlLinkPtr lk) {
2928
0
    xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2929
0
    if (ref == NULL) return;
2930
0
    if (ref->value != NULL)
2931
0
        xmlFree((xmlChar *)ref->value);
2932
0
    if (ref->name != NULL)
2933
0
        xmlFree((xmlChar *)ref->name);
2934
0
    xmlFree(ref);
2935
0
}
2936
2937
/**
2938
 * xmlFreeRefTableEntry:
2939
 * @list_ref:  A list of references.
2940
 *
2941
 * Deallocate the memory used by a list of references
2942
 */
2943
static void
2944
0
xmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2945
0
    xmlListPtr list_ref = (xmlListPtr) payload;
2946
0
    if (list_ref == NULL) return;
2947
0
    xmlListDelete(list_ref);
2948
0
}
2949
2950
/**
2951
 * xmlWalkRemoveRef:
2952
 * @data:  Contents of current link
2953
 * @user:  Value supplied by the user
2954
 *
2955
 * Returns 0 to abort the walk or 1 to continue
2956
 */
2957
static int
2958
xmlWalkRemoveRef(const void *data, void *user)
2959
0
{
2960
0
    xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2961
0
    xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2962
0
    xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2963
2964
0
    if (attr0 == attr1) { /* Matched: remove and terminate walk */
2965
0
        xmlListRemoveFirst(ref_list, (void *)data);
2966
0
        return 0;
2967
0
    }
2968
0
    return 1;
2969
0
}
2970
2971
/**
2972
 * xmlDummyCompare
2973
 * @data0:  Value supplied by the user
2974
 * @data1:  Value supplied by the user
2975
 *
2976
 * Do nothing, return 0. Used to create unordered lists.
2977
 */
2978
static int
2979
xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2980
                const void *data1 ATTRIBUTE_UNUSED)
2981
0
{
2982
0
    return (0);
2983
0
}
2984
2985
/**
2986
 * xmlAddRef:
2987
 * @ctxt:  the validation context
2988
 * @doc:  pointer to the document
2989
 * @value:  the value name
2990
 * @attr:  the attribute holding the Ref
2991
 *
2992
 * DEPRECATED, do not use. This function will be removed from the public API.
2993
 *
2994
 * Register a new ref declaration
2995
 *
2996
 * Returns NULL if not, otherwise the new xmlRefPtr
2997
 */
2998
xmlRefPtr
2999
xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
3000
0
    xmlAttrPtr attr) {
3001
0
    xmlRefPtr ret;
3002
0
    xmlRefTablePtr table;
3003
0
    xmlListPtr ref_list;
3004
3005
0
    if (doc == NULL) {
3006
0
        return(NULL);
3007
0
    }
3008
0
    if (value == NULL) {
3009
0
        return(NULL);
3010
0
    }
3011
0
    if (attr == NULL) {
3012
0
        return(NULL);
3013
0
    }
3014
3015
    /*
3016
     * Create the Ref table if needed.
3017
     */
3018
0
    table = (xmlRefTablePtr) doc->refs;
3019
0
    if (table == NULL) {
3020
0
        doc->refs = table = xmlHashCreateDict(0, doc->dict);
3021
0
    }
3022
0
    if (table == NULL) {
3023
0
  xmlVErrMemory(ctxt,
3024
0
            "xmlAddRef: Table creation failed!\n");
3025
0
        return(NULL);
3026
0
    }
3027
3028
0
    ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
3029
0
    if (ret == NULL) {
3030
0
  xmlVErrMemory(ctxt, "malloc failed");
3031
0
        return(NULL);
3032
0
    }
3033
3034
    /*
3035
     * fill the structure.
3036
     */
3037
0
    ret->value = xmlStrdup(value);
3038
0
    if (xmlIsStreaming(ctxt)) {
3039
  /*
3040
   * Operating in streaming mode, attr is gonna disappear
3041
   */
3042
0
  ret->name = xmlStrdup(attr->name);
3043
0
  ret->attr = NULL;
3044
0
    } else {
3045
0
  ret->name = NULL;
3046
0
  ret->attr = attr;
3047
0
    }
3048
0
    ret->lineno = xmlGetLineNo(attr->parent);
3049
3050
    /* To add a reference :-
3051
     * References are maintained as a list of references,
3052
     * Lookup the entry, if no entry create new nodelist
3053
     * Add the owning node to the NodeList
3054
     * Return the ref
3055
     */
3056
3057
0
    if (NULL == (ref_list = xmlHashLookup(table, value))) {
3058
0
        if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
3059
0
      xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3060
0
        "xmlAddRef: Reference list creation failed!\n",
3061
0
        NULL);
3062
0
      goto failed;
3063
0
        }
3064
0
        if (xmlHashAddEntry(table, value, ref_list) < 0) {
3065
0
            xmlListDelete(ref_list);
3066
0
      xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3067
0
        "xmlAddRef: Reference list insertion failed!\n",
3068
0
        NULL);
3069
0
      goto failed;
3070
0
        }
3071
0
    }
3072
0
    if (xmlListAppend(ref_list, ret) != 0) {
3073
0
  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3074
0
        "xmlAddRef: Reference list insertion failed!\n",
3075
0
        NULL);
3076
0
        goto failed;
3077
0
    }
3078
0
    return(ret);
3079
0
failed:
3080
0
    if (ret != NULL) {
3081
0
        if (ret->value != NULL)
3082
0
      xmlFree((char *)ret->value);
3083
0
        if (ret->name != NULL)
3084
0
      xmlFree((char *)ret->name);
3085
0
        xmlFree(ret);
3086
0
    }
3087
0
    return(NULL);
3088
0
}
3089
3090
/**
3091
 * xmlFreeRefTable:
3092
 * @table:  An ref table
3093
 *
3094
 * DEPRECATED, do not use. This function will be removed from the public API.
3095
 *
3096
 * Deallocate the memory used by an Ref hash table.
3097
 */
3098
void
3099
0
xmlFreeRefTable(xmlRefTablePtr table) {
3100
0
    xmlHashFree(table, xmlFreeRefTableEntry);
3101
0
}
3102
3103
/**
3104
 * xmlIsRef:
3105
 * @doc:  the document
3106
 * @elem:  the element carrying the attribute
3107
 * @attr:  the attribute
3108
 *
3109
 * DEPRECATED, do not use. This function will be removed from the public API.
3110
 *
3111
 * Determine whether an attribute is of type Ref. In case we have DTD(s)
3112
 * then this is simple, otherwise we use an heuristic: name Ref (upper
3113
 * or lowercase).
3114
 *
3115
 * Returns 0 or 1 depending on the lookup result
3116
 */
3117
int
3118
0
xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3119
0
    if (attr == NULL)
3120
0
        return(0);
3121
0
    if (doc == NULL) {
3122
0
        doc = attr->doc;
3123
0
  if (doc == NULL) return(0);
3124
0
    }
3125
3126
0
    if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3127
0
        return(0);
3128
0
    } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3129
        /* TODO @@@ */
3130
0
        return(0);
3131
0
    } else {
3132
0
        xmlAttributePtr attrDecl;
3133
3134
0
        if (elem == NULL) return(0);
3135
0
        attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3136
0
        if ((attrDecl == NULL) && (doc->extSubset != NULL))
3137
0
            attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3138
0
                             elem->name, attr->name);
3139
3140
0
  if ((attrDecl != NULL) &&
3141
0
      (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3142
0
       attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3143
0
  return(1);
3144
0
    }
3145
0
    return(0);
3146
0
}
3147
3148
/**
3149
 * xmlRemoveRef:
3150
 * @doc:  the document
3151
 * @attr:  the attribute
3152
 *
3153
 * DEPRECATED, do not use. This function will be removed from the public API.
3154
 *
3155
 * Remove the given attribute from the Ref table maintained internally.
3156
 *
3157
 * Returns -1 if the lookup failed and 0 otherwise
3158
 */
3159
int
3160
0
xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
3161
0
    xmlListPtr ref_list;
3162
0
    xmlRefTablePtr table;
3163
0
    xmlChar *ID;
3164
0
    xmlRemoveMemo target;
3165
3166
0
    if (doc == NULL) return(-1);
3167
0
    if (attr == NULL) return(-1);
3168
3169
0
    table = (xmlRefTablePtr) doc->refs;
3170
0
    if (table == NULL)
3171
0
        return(-1);
3172
3173
0
    ID = xmlNodeListGetString(doc, attr->children, 1);
3174
0
    if (ID == NULL)
3175
0
        return(-1);
3176
3177
0
    ref_list = xmlHashLookup(table, ID);
3178
0
    if(ref_list == NULL) {
3179
0
        xmlFree(ID);
3180
0
        return (-1);
3181
0
    }
3182
3183
    /* At this point, ref_list refers to a list of references which
3184
     * have the same key as the supplied attr. Our list of references
3185
     * is ordered by reference address and we don't have that information
3186
     * here to use when removing. We'll have to walk the list and
3187
     * check for a matching attribute, when we find one stop the walk
3188
     * and remove the entry.
3189
     * The list is ordered by reference, so that means we don't have the
3190
     * key. Passing the list and the reference to the walker means we
3191
     * will have enough data to be able to remove the entry.
3192
     */
3193
0
    target.l = ref_list;
3194
0
    target.ap = attr;
3195
3196
    /* Remove the supplied attr from our list */
3197
0
    xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3198
3199
    /*If the list is empty then remove the list entry in the hash */
3200
0
    if (xmlListEmpty(ref_list))
3201
0
        xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry);
3202
0
    xmlFree(ID);
3203
0
    return(0);
3204
0
}
3205
3206
/**
3207
 * xmlGetRefs:
3208
 * @doc:  pointer to the document
3209
 * @ID:  the ID value
3210
 *
3211
 * DEPRECATED, do not use. This function will be removed from the public API.
3212
 *
3213
 * Find the set of references for the supplied ID.
3214
 *
3215
 * Returns NULL if not found, otherwise node set for the ID.
3216
 */
3217
xmlListPtr
3218
0
xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
3219
0
    xmlRefTablePtr table;
3220
3221
0
    if (doc == NULL) {
3222
0
        return(NULL);
3223
0
    }
3224
3225
0
    if (ID == NULL) {
3226
0
        return(NULL);
3227
0
    }
3228
3229
0
    table = (xmlRefTablePtr) doc->refs;
3230
0
    if (table == NULL)
3231
0
        return(NULL);
3232
3233
0
    return (xmlHashLookup(table, ID));
3234
0
}
3235
3236
/************************************************************************
3237
 *                  *
3238
 *    Routines for validity checking        *
3239
 *                  *
3240
 ************************************************************************/
3241
3242
/**
3243
 * xmlGetDtdElementDesc:
3244
 * @dtd:  a pointer to the DtD to search
3245
 * @name:  the element name
3246
 *
3247
 * Search the DTD for the description of this element
3248
 *
3249
 * returns the xmlElementPtr if found or NULL
3250
 */
3251
3252
xmlElementPtr
3253
0
xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3254
0
    xmlElementTablePtr table;
3255
0
    xmlElementPtr cur;
3256
0
    xmlChar *uqname = NULL, *prefix = NULL;
3257
3258
0
    if ((dtd == NULL) || (name == NULL)) return(NULL);
3259
0
    if (dtd->elements == NULL)
3260
0
  return(NULL);
3261
0
    table = (xmlElementTablePtr) dtd->elements;
3262
3263
0
    uqname = xmlSplitQName2(name, &prefix);
3264
0
    if (uqname != NULL)
3265
0
        name = uqname;
3266
0
    cur = xmlHashLookup2(table, name, prefix);
3267
0
    if (prefix != NULL) xmlFree(prefix);
3268
0
    if (uqname != NULL) xmlFree(uqname);
3269
0
    return(cur);
3270
0
}
3271
/**
3272
 * xmlGetDtdElementDesc2:
3273
 * @dtd:  a pointer to the DtD to search
3274
 * @name:  the element name
3275
 * @create:  create an empty description if not found
3276
 *
3277
 * Search the DTD for the description of this element
3278
 *
3279
 * returns the xmlElementPtr if found or NULL
3280
 */
3281
3282
static xmlElementPtr
3283
xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
3284
0
                      int create) {
3285
0
    xmlElementTablePtr table;
3286
0
    xmlElementPtr cur;
3287
0
    xmlChar *uqname = NULL, *prefix = NULL;
3288
3289
0
    if (dtd == NULL) return(NULL);
3290
0
    if (dtd->elements == NULL) {
3291
0
  xmlDictPtr dict = NULL;
3292
3293
0
  if (dtd->doc != NULL)
3294
0
      dict = dtd->doc->dict;
3295
3296
0
  if (!create)
3297
0
      return(NULL);
3298
  /*
3299
   * Create the Element table if needed.
3300
   */
3301
0
  table = (xmlElementTablePtr) dtd->elements;
3302
0
  if (table == NULL) {
3303
0
      table = xmlHashCreateDict(0, dict);
3304
0
      dtd->elements = (void *) table;
3305
0
  }
3306
0
  if (table == NULL) {
3307
0
      xmlVErrMemory(ctxt, "element table allocation failed");
3308
0
      return(NULL);
3309
0
  }
3310
0
    }
3311
0
    table = (xmlElementTablePtr) dtd->elements;
3312
3313
0
    uqname = xmlSplitQName2(name, &prefix);
3314
0
    if (uqname != NULL)
3315
0
        name = uqname;
3316
0
    cur = xmlHashLookup2(table, name, prefix);
3317
0
    if ((cur == NULL) && (create)) {
3318
0
  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3319
0
  if (cur == NULL) {
3320
0
      xmlVErrMemory(ctxt, "malloc failed");
3321
0
      goto error;
3322
0
  }
3323
0
  memset(cur, 0, sizeof(xmlElement));
3324
0
  cur->type = XML_ELEMENT_DECL;
3325
3326
  /*
3327
   * fill the structure.
3328
   */
3329
0
  cur->name = xmlStrdup(name);
3330
0
  cur->prefix = xmlStrdup(prefix);
3331
0
  cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3332
3333
0
  if (xmlHashAddEntry2(table, name, prefix, cur) < 0) {
3334
0
      xmlVErrMemory(ctxt, "adding entry failed");
3335
0
            xmlFreeElement(cur);
3336
0
            cur = NULL;
3337
0
        }
3338
0
    }
3339
0
error:
3340
0
    if (prefix != NULL) xmlFree(prefix);
3341
0
    if (uqname != NULL) xmlFree(uqname);
3342
0
    return(cur);
3343
0
}
3344
3345
/**
3346
 * xmlGetDtdQElementDesc:
3347
 * @dtd:  a pointer to the DtD to search
3348
 * @name:  the element name
3349
 * @prefix:  the element namespace prefix
3350
 *
3351
 * Search the DTD for the description of this element
3352
 *
3353
 * returns the xmlElementPtr if found or NULL
3354
 */
3355
3356
xmlElementPtr
3357
xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3358
0
                const xmlChar *prefix) {
3359
0
    xmlElementTablePtr table;
3360
3361
0
    if (dtd == NULL) return(NULL);
3362
0
    if (dtd->elements == NULL) return(NULL);
3363
0
    table = (xmlElementTablePtr) dtd->elements;
3364
3365
0
    return(xmlHashLookup2(table, name, prefix));
3366
0
}
3367
3368
/**
3369
 * xmlGetDtdAttrDesc:
3370
 * @dtd:  a pointer to the DtD to search
3371
 * @elem:  the element name
3372
 * @name:  the attribute name
3373
 *
3374
 * Search the DTD for the description of this attribute on
3375
 * this element.
3376
 *
3377
 * returns the xmlAttributePtr if found or NULL
3378
 */
3379
3380
xmlAttributePtr
3381
0
xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3382
0
    xmlAttributeTablePtr table;
3383
0
    xmlAttributePtr cur;
3384
0
    xmlChar *uqname = NULL, *prefix = NULL;
3385
3386
0
    if (dtd == NULL) return(NULL);
3387
0
    if (dtd->attributes == NULL) return(NULL);
3388
3389
0
    table = (xmlAttributeTablePtr) dtd->attributes;
3390
0
    if (table == NULL)
3391
0
  return(NULL);
3392
3393
0
    uqname = xmlSplitQName2(name, &prefix);
3394
3395
0
    if (uqname != NULL) {
3396
0
  cur = xmlHashLookup3(table, uqname, prefix, elem);
3397
0
  if (prefix != NULL) xmlFree(prefix);
3398
0
  if (uqname != NULL) xmlFree(uqname);
3399
0
    } else
3400
0
  cur = xmlHashLookup3(table, name, NULL, elem);
3401
0
    return(cur);
3402
0
}
3403
3404
/**
3405
 * xmlGetDtdQAttrDesc:
3406
 * @dtd:  a pointer to the DtD to search
3407
 * @elem:  the element name
3408
 * @name:  the attribute name
3409
 * @prefix:  the attribute namespace prefix
3410
 *
3411
 * Search the DTD for the description of this qualified attribute on
3412
 * this element.
3413
 *
3414
 * returns the xmlAttributePtr if found or NULL
3415
 */
3416
3417
xmlAttributePtr
3418
xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3419
0
            const xmlChar *prefix) {
3420
0
    xmlAttributeTablePtr table;
3421
3422
0
    if (dtd == NULL) return(NULL);
3423
0
    if (dtd->attributes == NULL) return(NULL);
3424
0
    table = (xmlAttributeTablePtr) dtd->attributes;
3425
3426
0
    return(xmlHashLookup3(table, name, prefix, elem));
3427
0
}
3428
3429
/**
3430
 * xmlGetDtdNotationDesc:
3431
 * @dtd:  a pointer to the DtD to search
3432
 * @name:  the notation name
3433
 *
3434
 * Search the DTD for the description of this notation
3435
 *
3436
 * returns the xmlNotationPtr if found or NULL
3437
 */
3438
3439
xmlNotationPtr
3440
0
xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3441
0
    xmlNotationTablePtr table;
3442
3443
0
    if (dtd == NULL) return(NULL);
3444
0
    if (dtd->notations == NULL) return(NULL);
3445
0
    table = (xmlNotationTablePtr) dtd->notations;
3446
3447
0
    return(xmlHashLookup(table, name));
3448
0
}
3449
3450
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3451
/**
3452
 * xmlValidateNotationUse:
3453
 * @ctxt:  the validation context
3454
 * @doc:  the document
3455
 * @notationName:  the notation name to check
3456
 *
3457
 * Validate that the given name match a notation declaration.
3458
 * - [ VC: Notation Declared ]
3459
 *
3460
 * returns 1 if valid or 0 otherwise
3461
 */
3462
3463
int
3464
xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3465
0
                       const xmlChar *notationName) {
3466
0
    xmlNotationPtr notaDecl;
3467
0
    if ((doc == NULL) || (doc->intSubset == NULL) ||
3468
0
        (notationName == NULL)) return(-1);
3469
3470
0
    notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3471
0
    if ((notaDecl == NULL) && (doc->extSubset != NULL))
3472
0
  notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3473
3474
0
    if ((notaDecl == NULL) && (ctxt != NULL)) {
3475
0
  xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3476
0
                  "NOTATION %s is not declared\n",
3477
0
            notationName, NULL, NULL);
3478
0
  return(0);
3479
0
    }
3480
0
    return(1);
3481
0
}
3482
#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3483
3484
/**
3485
 * xmlIsMixedElement:
3486
 * @doc:  the document
3487
 * @name:  the element name
3488
 *
3489
 * Search in the DtDs whether an element accept Mixed content (or ANY)
3490
 * basically if it is supposed to accept text childs
3491
 *
3492
 * returns 0 if no, 1 if yes, and -1 if no element description is available
3493
 */
3494
3495
int
3496
0
xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3497
0
    xmlElementPtr elemDecl;
3498
3499
0
    if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3500
3501
0
    elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3502
0
    if ((elemDecl == NULL) && (doc->extSubset != NULL))
3503
0
  elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3504
0
    if (elemDecl == NULL) return(-1);
3505
0
    switch (elemDecl->etype) {
3506
0
  case XML_ELEMENT_TYPE_UNDEFINED:
3507
0
      return(-1);
3508
0
  case XML_ELEMENT_TYPE_ELEMENT:
3509
0
      return(0);
3510
0
        case XML_ELEMENT_TYPE_EMPTY:
3511
      /*
3512
       * return 1 for EMPTY since we want VC error to pop up
3513
       * on <empty>     </empty> for example
3514
       */
3515
0
  case XML_ELEMENT_TYPE_ANY:
3516
0
  case XML_ELEMENT_TYPE_MIXED:
3517
0
      return(1);
3518
0
    }
3519
0
    return(1);
3520
0
}
3521
3522
#ifdef LIBXML_VALID_ENABLED
3523
3524
static int
3525
0
xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3526
0
    if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3527
        /*
3528
   * Use the new checks of production [4] [4a] amd [5] of the
3529
   * Update 5 of XML-1.0
3530
   */
3531
0
  if (((c >= 'a') && (c <= 'z')) ||
3532
0
      ((c >= 'A') && (c <= 'Z')) ||
3533
0
      (c == '_') || (c == ':') ||
3534
0
      ((c >= 0xC0) && (c <= 0xD6)) ||
3535
0
      ((c >= 0xD8) && (c <= 0xF6)) ||
3536
0
      ((c >= 0xF8) && (c <= 0x2FF)) ||
3537
0
      ((c >= 0x370) && (c <= 0x37D)) ||
3538
0
      ((c >= 0x37F) && (c <= 0x1FFF)) ||
3539
0
      ((c >= 0x200C) && (c <= 0x200D)) ||
3540
0
      ((c >= 0x2070) && (c <= 0x218F)) ||
3541
0
      ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3542
0
      ((c >= 0x3001) && (c <= 0xD7FF)) ||
3543
0
      ((c >= 0xF900) && (c <= 0xFDCF)) ||
3544
0
      ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3545
0
      ((c >= 0x10000) && (c <= 0xEFFFF)))
3546
0
      return(1);
3547
0
    } else {
3548
0
        if (IS_LETTER(c) || (c == '_') || (c == ':'))
3549
0
      return(1);
3550
0
    }
3551
0
    return(0);
3552
0
}
3553
3554
static int
3555
0
xmlIsDocNameChar(xmlDocPtr doc, int c) {
3556
0
    if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3557
        /*
3558
   * Use the new checks of production [4] [4a] amd [5] of the
3559
   * Update 5 of XML-1.0
3560
   */
3561
0
  if (((c >= 'a') && (c <= 'z')) ||
3562
0
      ((c >= 'A') && (c <= 'Z')) ||
3563
0
      ((c >= '0') && (c <= '9')) || /* !start */
3564
0
      (c == '_') || (c == ':') ||
3565
0
      (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3566
0
      ((c >= 0xC0) && (c <= 0xD6)) ||
3567
0
      ((c >= 0xD8) && (c <= 0xF6)) ||
3568
0
      ((c >= 0xF8) && (c <= 0x2FF)) ||
3569
0
      ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3570
0
      ((c >= 0x370) && (c <= 0x37D)) ||
3571
0
      ((c >= 0x37F) && (c <= 0x1FFF)) ||
3572
0
      ((c >= 0x200C) && (c <= 0x200D)) ||
3573
0
      ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3574
0
      ((c >= 0x2070) && (c <= 0x218F)) ||
3575
0
      ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3576
0
      ((c >= 0x3001) && (c <= 0xD7FF)) ||
3577
0
      ((c >= 0xF900) && (c <= 0xFDCF)) ||
3578
0
      ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3579
0
      ((c >= 0x10000) && (c <= 0xEFFFF)))
3580
0
       return(1);
3581
0
    } else {
3582
0
        if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3583
0
            (c == '.') || (c == '-') ||
3584
0
      (c == '_') || (c == ':') ||
3585
0
      (IS_COMBINING(c)) ||
3586
0
      (IS_EXTENDER(c)))
3587
0
      return(1);
3588
0
    }
3589
0
    return(0);
3590
0
}
3591
3592
/**
3593
 * xmlValidateNameValue:
3594
 * @doc:  pointer to the document or NULL
3595
 * @value:  an Name value
3596
 *
3597
 * Validate that the given value match Name production
3598
 *
3599
 * returns 1 if valid or 0 otherwise
3600
 */
3601
3602
static int
3603
0
xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3604
0
    const xmlChar *cur;
3605
0
    int val, len;
3606
3607
0
    if (value == NULL) return(0);
3608
0
    cur = value;
3609
0
    val = xmlStringCurrentChar(NULL, cur, &len);
3610
0
    cur += len;
3611
0
    if (!xmlIsDocNameStartChar(doc, val))
3612
0
  return(0);
3613
3614
0
    val = xmlStringCurrentChar(NULL, cur, &len);
3615
0
    cur += len;
3616
0
    while (xmlIsDocNameChar(doc, val)) {
3617
0
  val = xmlStringCurrentChar(NULL, cur, &len);
3618
0
  cur += len;
3619
0
    }
3620
3621
0
    if (val != 0) return(0);
3622
3623
0
    return(1);
3624
0
}
3625
3626
/**
3627
 * xmlValidateNameValue:
3628
 * @value:  an Name value
3629
 *
3630
 * Validate that the given value match Name production
3631
 *
3632
 * returns 1 if valid or 0 otherwise
3633
 */
3634
3635
int
3636
0
xmlValidateNameValue(const xmlChar *value) {
3637
0
    return(xmlValidateNameValueInternal(NULL, value));
3638
0
}
3639
3640
/**
3641
 * xmlValidateNamesValueInternal:
3642
 * @doc:  pointer to the document or NULL
3643
 * @value:  an Names value
3644
 *
3645
 * Validate that the given value match Names production
3646
 *
3647
 * returns 1 if valid or 0 otherwise
3648
 */
3649
3650
static int
3651
0
xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3652
0
    const xmlChar *cur;
3653
0
    int val, len;
3654
3655
0
    if (value == NULL) return(0);
3656
0
    cur = value;
3657
0
    val = xmlStringCurrentChar(NULL, cur, &len);
3658
0
    cur += len;
3659
3660
0
    if (!xmlIsDocNameStartChar(doc, val))
3661
0
  return(0);
3662
3663
0
    val = xmlStringCurrentChar(NULL, cur, &len);
3664
0
    cur += len;
3665
0
    while (xmlIsDocNameChar(doc, val)) {
3666
0
  val = xmlStringCurrentChar(NULL, cur, &len);
3667
0
  cur += len;
3668
0
    }
3669
3670
    /* Should not test IS_BLANK(val) here -- see erratum E20*/
3671
0
    while (val == 0x20) {
3672
0
  while (val == 0x20) {
3673
0
      val = xmlStringCurrentChar(NULL, cur, &len);
3674
0
      cur += len;
3675
0
  }
3676
3677
0
  if (!xmlIsDocNameStartChar(doc, val))
3678
0
      return(0);
3679
3680
0
  val = xmlStringCurrentChar(NULL, cur, &len);
3681
0
  cur += len;
3682
3683
0
  while (xmlIsDocNameChar(doc, val)) {
3684
0
      val = xmlStringCurrentChar(NULL, cur, &len);
3685
0
      cur += len;
3686
0
  }
3687
0
    }
3688
3689
0
    if (val != 0) return(0);
3690
3691
0
    return(1);
3692
0
}
3693
3694
/**
3695
 * xmlValidateNamesValue:
3696
 * @value:  an Names value
3697
 *
3698
 * Validate that the given value match Names production
3699
 *
3700
 * returns 1 if valid or 0 otherwise
3701
 */
3702
3703
int
3704
0
xmlValidateNamesValue(const xmlChar *value) {
3705
0
    return(xmlValidateNamesValueInternal(NULL, value));
3706
0
}
3707
3708
/**
3709
 * xmlValidateNmtokenValueInternal:
3710
 * @doc:  pointer to the document or NULL
3711
 * @value:  an Nmtoken value
3712
 *
3713
 * Validate that the given value match Nmtoken production
3714
 *
3715
 * [ VC: Name Token ]
3716
 *
3717
 * returns 1 if valid or 0 otherwise
3718
 */
3719
3720
static int
3721
0
xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3722
0
    const xmlChar *cur;
3723
0
    int val, len;
3724
3725
0
    if (value == NULL) return(0);
3726
0
    cur = value;
3727
0
    val = xmlStringCurrentChar(NULL, cur, &len);
3728
0
    cur += len;
3729
3730
0
    if (!xmlIsDocNameChar(doc, val))
3731
0
  return(0);
3732
3733
0
    val = xmlStringCurrentChar(NULL, cur, &len);
3734
0
    cur += len;
3735
0
    while (xmlIsDocNameChar(doc, val)) {
3736
0
  val = xmlStringCurrentChar(NULL, cur, &len);
3737
0
  cur += len;
3738
0
    }
3739
3740
0
    if (val != 0) return(0);
3741
3742
0
    return(1);
3743
0
}
3744
3745
/**
3746
 * xmlValidateNmtokenValue:
3747
 * @value:  an Nmtoken value
3748
 *
3749
 * Validate that the given value match Nmtoken production
3750
 *
3751
 * [ VC: Name Token ]
3752
 *
3753
 * returns 1 if valid or 0 otherwise
3754
 */
3755
3756
int
3757
0
xmlValidateNmtokenValue(const xmlChar *value) {
3758
0
    return(xmlValidateNmtokenValueInternal(NULL, value));
3759
0
}
3760
3761
/**
3762
 * xmlValidateNmtokensValueInternal:
3763
 * @doc:  pointer to the document or NULL
3764
 * @value:  an Nmtokens value
3765
 *
3766
 * Validate that the given value match Nmtokens production
3767
 *
3768
 * [ VC: Name Token ]
3769
 *
3770
 * returns 1 if valid or 0 otherwise
3771
 */
3772
3773
static int
3774
0
xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3775
0
    const xmlChar *cur;
3776
0
    int val, len;
3777
3778
0
    if (value == NULL) return(0);
3779
0
    cur = value;
3780
0
    val = xmlStringCurrentChar(NULL, cur, &len);
3781
0
    cur += len;
3782
3783
0
    while (IS_BLANK(val)) {
3784
0
  val = xmlStringCurrentChar(NULL, cur, &len);
3785
0
  cur += len;
3786
0
    }
3787
3788
0
    if (!xmlIsDocNameChar(doc, val))
3789
0
  return(0);
3790
3791
0
    while (xmlIsDocNameChar(doc, val)) {
3792
0
  val = xmlStringCurrentChar(NULL, cur, &len);
3793
0
  cur += len;
3794
0
    }
3795
3796
    /* Should not test IS_BLANK(val) here -- see erratum E20*/
3797
0
    while (val == 0x20) {
3798
0
  while (val == 0x20) {
3799
0
      val = xmlStringCurrentChar(NULL, cur, &len);
3800
0
      cur += len;
3801
0
  }
3802
0
  if (val == 0) return(1);
3803
3804
0
  if (!xmlIsDocNameChar(doc, val))
3805
0
      return(0);
3806
3807
0
  val = xmlStringCurrentChar(NULL, cur, &len);
3808
0
  cur += len;
3809
3810
0
  while (xmlIsDocNameChar(doc, val)) {
3811
0
      val = xmlStringCurrentChar(NULL, cur, &len);
3812
0
      cur += len;
3813
0
  }
3814
0
    }
3815
3816
0
    if (val != 0) return(0);
3817
3818
0
    return(1);
3819
0
}
3820
3821
/**
3822
 * xmlValidateNmtokensValue:
3823
 * @value:  an Nmtokens value
3824
 *
3825
 * Validate that the given value match Nmtokens production
3826
 *
3827
 * [ VC: Name Token ]
3828
 *
3829
 * returns 1 if valid or 0 otherwise
3830
 */
3831
3832
int
3833
0
xmlValidateNmtokensValue(const xmlChar *value) {
3834
0
    return(xmlValidateNmtokensValueInternal(NULL, value));
3835
0
}
3836
3837
/**
3838
 * xmlValidateNotationDecl:
3839
 * @ctxt:  the validation context
3840
 * @doc:  a document instance
3841
 * @nota:  a notation definition
3842
 *
3843
 * Try to validate a single notation definition
3844
 * basically it does the following checks as described by the
3845
 * XML-1.0 recommendation:
3846
 *  - it seems that no validity constraint exists on notation declarations
3847
 * But this function get called anyway ...
3848
 *
3849
 * returns 1 if valid or 0 otherwise
3850
 */
3851
3852
int
3853
xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3854
0
                         xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3855
0
    int ret = 1;
3856
3857
0
    return(ret);
3858
0
}
3859
3860
/**
3861
 * xmlValidateAttributeValueInternal:
3862
 * @doc: the document
3863
 * @type:  an attribute type
3864
 * @value:  an attribute value
3865
 *
3866
 * Validate that the given attribute value match  the proper production
3867
 *
3868
 * returns 1 if valid or 0 otherwise
3869
 */
3870
3871
static int
3872
xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3873
0
                                  const xmlChar *value) {
3874
0
    switch (type) {
3875
0
  case XML_ATTRIBUTE_ENTITIES:
3876
0
  case XML_ATTRIBUTE_IDREFS:
3877
0
      return(xmlValidateNamesValueInternal(doc, value));
3878
0
  case XML_ATTRIBUTE_ENTITY:
3879
0
  case XML_ATTRIBUTE_IDREF:
3880
0
  case XML_ATTRIBUTE_ID:
3881
0
  case XML_ATTRIBUTE_NOTATION:
3882
0
      return(xmlValidateNameValueInternal(doc, value));
3883
0
  case XML_ATTRIBUTE_NMTOKENS:
3884
0
  case XML_ATTRIBUTE_ENUMERATION:
3885
0
      return(xmlValidateNmtokensValueInternal(doc, value));
3886
0
  case XML_ATTRIBUTE_NMTOKEN:
3887
0
      return(xmlValidateNmtokenValueInternal(doc, value));
3888
0
        case XML_ATTRIBUTE_CDATA:
3889
0
      break;
3890
0
    }
3891
0
    return(1);
3892
0
}
3893
3894
/**
3895
 * xmlValidateAttributeValue:
3896
 * @type:  an attribute type
3897
 * @value:  an attribute value
3898
 *
3899
 * Validate that the given attribute value match  the proper production
3900
 *
3901
 * [ VC: ID ]
3902
 * Values of type ID must match the Name production....
3903
 *
3904
 * [ VC: IDREF ]
3905
 * Values of type IDREF must match the Name production, and values
3906
 * of type IDREFS must match Names ...
3907
 *
3908
 * [ VC: Entity Name ]
3909
 * Values of type ENTITY must match the Name production, values
3910
 * of type ENTITIES must match Names ...
3911
 *
3912
 * [ VC: Name Token ]
3913
 * Values of type NMTOKEN must match the Nmtoken production; values
3914
 * of type NMTOKENS must match Nmtokens.
3915
 *
3916
 * returns 1 if valid or 0 otherwise
3917
 */
3918
int
3919
0
xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3920
0
    return(xmlValidateAttributeValueInternal(NULL, type, value));
3921
0
}
3922
3923
/**
3924
 * xmlValidateAttributeValue2:
3925
 * @ctxt:  the validation context
3926
 * @doc:  the document
3927
 * @name:  the attribute name (used for error reporting only)
3928
 * @type:  the attribute type
3929
 * @value:  the attribute value
3930
 *
3931
 * Validate that the given attribute value match a given type.
3932
 * This typically cannot be done before having finished parsing
3933
 * the subsets.
3934
 *
3935
 * [ VC: IDREF ]
3936
 * Values of type IDREF must match one of the declared IDs
3937
 * Values of type IDREFS must match a sequence of the declared IDs
3938
 * each Name must match the value of an ID attribute on some element
3939
 * in the XML document; i.e. IDREF values must match the value of
3940
 * some ID attribute
3941
 *
3942
 * [ VC: Entity Name ]
3943
 * Values of type ENTITY must match one declared entity
3944
 * Values of type ENTITIES must match a sequence of declared entities
3945
 *
3946
 * [ VC: Notation Attributes ]
3947
 * all notation names in the declaration must be declared.
3948
 *
3949
 * returns 1 if valid or 0 otherwise
3950
 */
3951
3952
static int
3953
xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3954
0
      const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3955
0
    int ret = 1;
3956
0
    switch (type) {
3957
0
  case XML_ATTRIBUTE_IDREFS:
3958
0
  case XML_ATTRIBUTE_IDREF:
3959
0
  case XML_ATTRIBUTE_ID:
3960
0
  case XML_ATTRIBUTE_NMTOKENS:
3961
0
  case XML_ATTRIBUTE_ENUMERATION:
3962
0
  case XML_ATTRIBUTE_NMTOKEN:
3963
0
        case XML_ATTRIBUTE_CDATA:
3964
0
      break;
3965
0
  case XML_ATTRIBUTE_ENTITY: {
3966
0
      xmlEntityPtr ent;
3967
3968
0
      ent = xmlGetDocEntity(doc, value);
3969
      /* yeah it's a bit messy... */
3970
0
      if ((ent == NULL) && (doc->standalone == 1)) {
3971
0
    doc->standalone = 0;
3972
0
    ent = xmlGetDocEntity(doc, value);
3973
0
      }
3974
0
      if (ent == NULL) {
3975
0
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3976
0
        XML_DTD_UNKNOWN_ENTITY,
3977
0
   "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3978
0
           name, value, NULL);
3979
0
    ret = 0;
3980
0
      } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3981
0
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3982
0
        XML_DTD_ENTITY_TYPE,
3983
0
   "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3984
0
           name, value, NULL);
3985
0
    ret = 0;
3986
0
      }
3987
0
      break;
3988
0
        }
3989
0
  case XML_ATTRIBUTE_ENTITIES: {
3990
0
      xmlChar *dup, *nam = NULL, *cur, save;
3991
0
      xmlEntityPtr ent;
3992
3993
0
      dup = xmlStrdup(value);
3994
0
      if (dup == NULL)
3995
0
    return(0);
3996
0
      cur = dup;
3997
0
      while (*cur != 0) {
3998
0
    nam = cur;
3999
0
    while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
4000
0
    save = *cur;
4001
0
    *cur = 0;
4002
0
    ent = xmlGetDocEntity(doc, nam);
4003
0
    if (ent == NULL) {
4004
0
        xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4005
0
            XML_DTD_UNKNOWN_ENTITY,
4006
0
       "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
4007
0
         name, nam, NULL);
4008
0
        ret = 0;
4009
0
    } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4010
0
        xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4011
0
            XML_DTD_ENTITY_TYPE,
4012
0
       "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
4013
0
         name, nam, NULL);
4014
0
        ret = 0;
4015
0
    }
4016
0
    if (save == 0)
4017
0
        break;
4018
0
    *cur = save;
4019
0
    while (IS_BLANK_CH(*cur)) cur++;
4020
0
      }
4021
0
      xmlFree(dup);
4022
0
      break;
4023
0
  }
4024
0
  case XML_ATTRIBUTE_NOTATION: {
4025
0
      xmlNotationPtr nota;
4026
4027
0
      nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4028
0
      if ((nota == NULL) && (doc->extSubset != NULL))
4029
0
    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4030
4031
0
      if (nota == NULL) {
4032
0
    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4033
0
                    XML_DTD_UNKNOWN_NOTATION,
4034
0
       "NOTATION attribute %s reference an unknown notation \"%s\"\n",
4035
0
           name, value, NULL);
4036
0
    ret = 0;
4037
0
      }
4038
0
      break;
4039
0
        }
4040
0
    }
4041
0
    return(ret);
4042
0
}
4043
4044
/**
4045
 * xmlValidCtxtNormalizeAttributeValue:
4046
 * @ctxt: the validation context
4047
 * @doc:  the document
4048
 * @elem:  the parent
4049
 * @name:  the attribute name
4050
 * @value:  the attribute value
4051
 * @ctxt:  the validation context or NULL
4052
 *
4053
 * Does the validation related extra step of the normalization of attribute
4054
 * values:
4055
 *
4056
 * If the declared value is not CDATA, then the XML processor must further
4057
 * process the normalized attribute value by discarding any leading and
4058
 * trailing space (#x20) characters, and by replacing sequences of space
4059
 * (#x20) characters by single space (#x20) character.
4060
 *
4061
 * Also  check VC: Standalone Document Declaration in P32, and update
4062
 *  ctxt->valid accordingly
4063
 *
4064
 * returns a new normalized string if normalization is needed, NULL otherwise
4065
 *      the caller must free the returned value.
4066
 */
4067
4068
xmlChar *
4069
xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4070
0
       xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4071
0
    xmlChar *ret;
4072
0
    xmlAttributePtr attrDecl = NULL;
4073
0
    int extsubset = 0;
4074
4075
0
    if (doc == NULL) return(NULL);
4076
0
    if (elem == NULL) return(NULL);
4077
0
    if (name == NULL) return(NULL);
4078
0
    if (value == NULL) return(NULL);
4079
4080
0
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4081
0
  xmlChar fn[50];
4082
0
  xmlChar *fullname;
4083
4084
0
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4085
0
  if (fullname == NULL)
4086
0
      return(NULL);
4087
0
  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4088
0
  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4089
0
      attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4090
0
      if (attrDecl != NULL)
4091
0
    extsubset = 1;
4092
0
  }
4093
0
  if ((fullname != fn) && (fullname != elem->name))
4094
0
      xmlFree(fullname);
4095
0
    }
4096
0
    if ((attrDecl == NULL) && (doc->intSubset != NULL))
4097
0
  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4098
0
    if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4099
0
  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4100
0
  if (attrDecl != NULL)
4101
0
      extsubset = 1;
4102
0
    }
4103
4104
0
    if (attrDecl == NULL)
4105
0
  return(NULL);
4106
0
    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4107
0
  return(NULL);
4108
4109
0
    ret = xmlStrdup(value);
4110
0
    if (ret == NULL)
4111
0
  return(NULL);
4112
0
    xmlValidNormalizeString(ret);
4113
0
    if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4114
0
  xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4115
0
"standalone: %s on %s value had to be normalized based on external subset declaration\n",
4116
0
         name, elem->name, NULL);
4117
0
  ctxt->valid = 0;
4118
0
    }
4119
0
    return(ret);
4120
0
}
4121
4122
/**
4123
 * xmlValidNormalizeAttributeValue:
4124
 * @doc:  the document
4125
 * @elem:  the parent
4126
 * @name:  the attribute name
4127
 * @value:  the attribute value
4128
 *
4129
 * Does the validation related extra step of the normalization of attribute
4130
 * values:
4131
 *
4132
 * If the declared value is not CDATA, then the XML processor must further
4133
 * process the normalized attribute value by discarding any leading and
4134
 * trailing space (#x20) characters, and by replacing sequences of space
4135
 * (#x20) characters by single space (#x20) character.
4136
 *
4137
 * Returns a new normalized string if normalization is needed, NULL otherwise
4138
 *      the caller must free the returned value.
4139
 */
4140
4141
xmlChar *
4142
xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4143
0
              const xmlChar *name, const xmlChar *value) {
4144
0
    xmlChar *ret;
4145
0
    xmlAttributePtr attrDecl = NULL;
4146
4147
0
    if (doc == NULL) return(NULL);
4148
0
    if (elem == NULL) return(NULL);
4149
0
    if (name == NULL) return(NULL);
4150
0
    if (value == NULL) return(NULL);
4151
4152
0
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4153
0
  xmlChar fn[50];
4154
0
  xmlChar *fullname;
4155
4156
0
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4157
0
  if (fullname == NULL)
4158
0
      return(NULL);
4159
0
  if ((fullname != fn) && (fullname != elem->name))
4160
0
      xmlFree(fullname);
4161
0
    }
4162
0
    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4163
0
    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4164
0
  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4165
4166
0
    if (attrDecl == NULL)
4167
0
  return(NULL);
4168
0
    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4169
0
  return(NULL);
4170
4171
0
    ret = xmlStrdup(value);
4172
0
    if (ret == NULL)
4173
0
  return(NULL);
4174
0
    xmlValidNormalizeString(ret);
4175
0
    return(ret);
4176
0
}
4177
4178
static void
4179
xmlValidateAttributeIdCallback(void *payload, void *data,
4180
0
                         const xmlChar *name ATTRIBUTE_UNUSED) {
4181
0
    xmlAttributePtr attr = (xmlAttributePtr) payload;
4182
0
    int *count = (int *) data;
4183
0
    if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4184
0
}
4185
4186
/**
4187
 * xmlValidateAttributeDecl:
4188
 * @ctxt:  the validation context
4189
 * @doc:  a document instance
4190
 * @attr:  an attribute definition
4191
 *
4192
 * Try to validate a single attribute definition
4193
 * basically it does the following checks as described by the
4194
 * XML-1.0 recommendation:
4195
 *  - [ VC: Attribute Default Legal ]
4196
 *  - [ VC: Enumeration ]
4197
 *  - [ VC: ID Attribute Default ]
4198
 *
4199
 * The ID/IDREF uniqueness and matching are done separately
4200
 *
4201
 * returns 1 if valid or 0 otherwise
4202
 */
4203
4204
int
4205
xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4206
0
                         xmlAttributePtr attr) {
4207
0
    int ret = 1;
4208
0
    int val;
4209
0
    CHECK_DTD;
4210
0
    if(attr == NULL) return(1);
4211
4212
    /* Attribute Default Legal */
4213
    /* Enumeration */
4214
0
    if (attr->defaultValue != NULL) {
4215
0
  val = xmlValidateAttributeValueInternal(doc, attr->atype,
4216
0
                                          attr->defaultValue);
4217
0
  if (val == 0) {
4218
0
      xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4219
0
         "Syntax of default value for attribute %s of %s is not valid\n",
4220
0
             attr->name, attr->elem, NULL);
4221
0
  }
4222
0
        ret &= val;
4223
0
    }
4224
4225
    /* ID Attribute Default */
4226
0
    if ((attr->atype == XML_ATTRIBUTE_ID)&&
4227
0
        (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4228
0
  (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4229
0
  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4230
0
          "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4231
0
         attr->name, attr->elem, NULL);
4232
0
  ret = 0;
4233
0
    }
4234
4235
    /* One ID per Element Type */
4236
0
    if (attr->atype == XML_ATTRIBUTE_ID) {
4237
0
        int nbId;
4238
4239
  /* the trick is that we parse DtD as their own internal subset */
4240
0
        xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4241
0
                                            attr->elem);
4242
0
  if (elem != NULL) {
4243
0
      nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4244
0
  } else {
4245
0
      xmlAttributeTablePtr table;
4246
4247
      /*
4248
       * The attribute may be declared in the internal subset and the
4249
       * element in the external subset.
4250
       */
4251
0
      nbId = 0;
4252
0
      if (doc->intSubset != NULL) {
4253
0
    table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4254
0
    xmlHashScan3(table, NULL, NULL, attr->elem,
4255
0
           xmlValidateAttributeIdCallback, &nbId);
4256
0
      }
4257
0
  }
4258
0
  if (nbId > 1) {
4259
4260
0
      xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4261
0
       "Element %s has %d ID attribute defined in the internal subset : %s\n",
4262
0
       attr->elem, nbId, attr->name);
4263
0
  } else if (doc->extSubset != NULL) {
4264
0
      int extId = 0;
4265
0
      elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4266
0
      if (elem != NULL) {
4267
0
    extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4268
0
      }
4269
0
      if (extId > 1) {
4270
0
    xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4271
0
       "Element %s has %d ID attribute defined in the external subset : %s\n",
4272
0
           attr->elem, extId, attr->name);
4273
0
      } else if (extId + nbId > 1) {
4274
0
    xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4275
0
"Element %s has ID attributes defined in the internal and external subset : %s\n",
4276
0
           attr->elem, attr->name, NULL);
4277
0
      }
4278
0
  }
4279
0
    }
4280
4281
    /* Validity Constraint: Enumeration */
4282
0
    if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4283
0
        xmlEnumerationPtr tree = attr->tree;
4284
0
  while (tree != NULL) {
4285
0
      if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4286
0
      tree = tree->next;
4287
0
  }
4288
0
  if (tree == NULL) {
4289
0
      xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4290
0
"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4291
0
       attr->defaultValue, attr->name, attr->elem);
4292
0
      ret = 0;
4293
0
  }
4294
0
    }
4295
4296
0
    return(ret);
4297
0
}
4298
4299
/**
4300
 * xmlValidateElementDecl:
4301
 * @ctxt:  the validation context
4302
 * @doc:  a document instance
4303
 * @elem:  an element definition
4304
 *
4305
 * Try to validate a single element definition
4306
 * basically it does the following checks as described by the
4307
 * XML-1.0 recommendation:
4308
 *  - [ VC: One ID per Element Type ]
4309
 *  - [ VC: No Duplicate Types ]
4310
 *  - [ VC: Unique Element Type Declaration ]
4311
 *
4312
 * returns 1 if valid or 0 otherwise
4313
 */
4314
4315
int
4316
xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4317
0
                       xmlElementPtr elem) {
4318
0
    int ret = 1;
4319
0
    xmlElementPtr tst;
4320
4321
0
    CHECK_DTD;
4322
4323
0
    if (elem == NULL) return(1);
4324
4325
#if 0
4326
#ifdef LIBXML_REGEXP_ENABLED
4327
    /* Build the regexp associated to the content model */
4328
    ret = xmlValidBuildContentModel(ctxt, elem);
4329
#endif
4330
#endif
4331
4332
    /* No Duplicate Types */
4333
0
    if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4334
0
  xmlElementContentPtr cur, next;
4335
0
        const xmlChar *name;
4336
4337
0
  cur = elem->content;
4338
0
  while (cur != NULL) {
4339
0
      if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4340
0
      if (cur->c1 == NULL) break;
4341
0
      if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4342
0
    name = cur->c1->name;
4343
0
    next = cur->c2;
4344
0
    while (next != NULL) {
4345
0
        if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4346
0
            if ((xmlStrEqual(next->name, name)) &&
4347
0
          (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4348
0
          if (cur->c1->prefix == NULL) {
4349
0
        xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4350
0
       "Definition of %s has duplicate references of %s\n",
4351
0
               elem->name, name, NULL);
4352
0
          } else {
4353
0
        xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4354
0
       "Definition of %s has duplicate references of %s:%s\n",
4355
0
               elem->name, cur->c1->prefix, name);
4356
0
          }
4357
0
          ret = 0;
4358
0
      }
4359
0
      break;
4360
0
        }
4361
0
        if (next->c1 == NULL) break;
4362
0
        if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4363
0
        if ((xmlStrEqual(next->c1->name, name)) &&
4364
0
            (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4365
0
      if (cur->c1->prefix == NULL) {
4366
0
          xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4367
0
         "Definition of %s has duplicate references to %s\n",
4368
0
           elem->name, name, NULL);
4369
0
      } else {
4370
0
          xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4371
0
         "Definition of %s has duplicate references to %s:%s\n",
4372
0
           elem->name, cur->c1->prefix, name);
4373
0
      }
4374
0
      ret = 0;
4375
0
        }
4376
0
        next = next->c2;
4377
0
    }
4378
0
      }
4379
0
      cur = cur->c2;
4380
0
  }
4381
0
    }
4382
4383
    /* VC: Unique Element Type Declaration */
4384
0
    tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4385
0
    if ((tst != NULL ) && (tst != elem) &&
4386
0
  ((tst->prefix == elem->prefix) ||
4387
0
   (xmlStrEqual(tst->prefix, elem->prefix))) &&
4388
0
  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4389
0
  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4390
0
                  "Redefinition of element %s\n",
4391
0
           elem->name, NULL, NULL);
4392
0
  ret = 0;
4393
0
    }
4394
0
    tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4395
0
    if ((tst != NULL ) && (tst != elem) &&
4396
0
  ((tst->prefix == elem->prefix) ||
4397
0
   (xmlStrEqual(tst->prefix, elem->prefix))) &&
4398
0
  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4399
0
  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4400
0
                  "Redefinition of element %s\n",
4401
0
           elem->name, NULL, NULL);
4402
0
  ret = 0;
4403
0
    }
4404
    /* One ID per Element Type
4405
     * already done when registering the attribute
4406
    if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4407
  ret = 0;
4408
    } */
4409
0
    return(ret);
4410
0
}
4411
4412
/**
4413
 * xmlValidateOneAttribute:
4414
 * @ctxt:  the validation context
4415
 * @doc:  a document instance
4416
 * @elem:  an element instance
4417
 * @attr:  an attribute instance
4418
 * @value:  the attribute value (without entities processing)
4419
 *
4420
 * Try to validate a single attribute for an element
4421
 * basically it does the following checks as described by the
4422
 * XML-1.0 recommendation:
4423
 *  - [ VC: Attribute Value Type ]
4424
 *  - [ VC: Fixed Attribute Default ]
4425
 *  - [ VC: Entity Name ]
4426
 *  - [ VC: Name Token ]
4427
 *  - [ VC: ID ]
4428
 *  - [ VC: IDREF ]
4429
 *  - [ VC: Entity Name ]
4430
 *  - [ VC: Notation Attributes ]
4431
 *
4432
 * The ID/IDREF uniqueness and matching are done separately
4433
 *
4434
 * returns 1 if valid or 0 otherwise
4435
 */
4436
4437
int
4438
xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4439
                        xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4440
0
{
4441
0
    xmlAttributePtr attrDecl =  NULL;
4442
0
    int val;
4443
0
    int ret = 1;
4444
4445
0
    CHECK_DTD;
4446
0
    if ((elem == NULL) || (elem->name == NULL)) return(0);
4447
0
    if ((attr == NULL) || (attr->name == NULL)) return(0);
4448
4449
0
    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4450
0
  xmlChar fn[50];
4451
0
  xmlChar *fullname;
4452
4453
0
  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4454
0
  if (fullname == NULL)
4455
0
      return(0);
4456
0
  if (attr->ns != NULL) {
4457
0
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4458
0
                              attr->name, attr->ns->prefix);
4459
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4460
0
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4461
0
                attr->name, attr->ns->prefix);
4462
0
  } else {
4463
0
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4464
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4465
0
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4466
0
               fullname, attr->name);
4467
0
  }
4468
0
  if ((fullname != fn) && (fullname != elem->name))
4469
0
      xmlFree(fullname);
4470
0
    }
4471
0
    if (attrDecl == NULL) {
4472
0
  if (attr->ns != NULL) {
4473
0
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4474
0
                              attr->name, attr->ns->prefix);
4475
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4476
0
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4477
0
                attr->name, attr->ns->prefix);
4478
0
  } else {
4479
0
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4480
0
                             elem->name, attr->name);
4481
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4482
0
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4483
0
               elem->name, attr->name);
4484
0
  }
4485
0
    }
4486
4487
4488
    /* Validity Constraint: Attribute Value Type */
4489
0
    if (attrDecl == NULL) {
4490
0
  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4491
0
         "No declaration for attribute %s of element %s\n",
4492
0
         attr->name, elem->name, NULL);
4493
0
  return(0);
4494
0
    }
4495
0
    attr->atype = attrDecl->atype;
4496
4497
0
    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4498
0
    if (val == 0) {
4499
0
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4500
0
     "Syntax of value for attribute %s of %s is not valid\n",
4501
0
         attr->name, elem->name, NULL);
4502
0
        ret = 0;
4503
0
    }
4504
4505
    /* Validity constraint: Fixed Attribute Default */
4506
0
    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4507
0
  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4508
0
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4509
0
     "Value for attribute %s of %s is different from default \"%s\"\n",
4510
0
       attr->name, elem->name, attrDecl->defaultValue);
4511
0
      ret = 0;
4512
0
  }
4513
0
    }
4514
4515
    /* Validity Constraint: ID uniqueness */
4516
0
    if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4517
0
        if (xmlAddID(ctxt, doc, value, attr) == NULL)
4518
0
      ret = 0;
4519
0
    }
4520
4521
0
    if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4522
0
  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4523
0
        if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4524
0
      ret = 0;
4525
0
    }
4526
4527
    /* Validity Constraint: Notation Attributes */
4528
0
    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4529
0
        xmlEnumerationPtr tree = attrDecl->tree;
4530
0
        xmlNotationPtr nota;
4531
4532
        /* First check that the given NOTATION was declared */
4533
0
  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4534
0
  if (nota == NULL)
4535
0
      nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4536
4537
0
  if (nota == NULL) {
4538
0
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4539
0
       "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4540
0
       value, attr->name, elem->name);
4541
0
      ret = 0;
4542
0
        }
4543
4544
  /* Second, verify that it's among the list */
4545
0
  while (tree != NULL) {
4546
0
      if (xmlStrEqual(tree->name, value)) break;
4547
0
      tree = tree->next;
4548
0
  }
4549
0
  if (tree == NULL) {
4550
0
      xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4551
0
"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4552
0
       value, attr->name, elem->name);
4553
0
      ret = 0;
4554
0
  }
4555
0
    }
4556
4557
    /* Validity Constraint: Enumeration */
4558
0
    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4559
0
        xmlEnumerationPtr tree = attrDecl->tree;
4560
0
  while (tree != NULL) {
4561
0
      if (xmlStrEqual(tree->name, value)) break;
4562
0
      tree = tree->next;
4563
0
  }
4564
0
  if (tree == NULL) {
4565
0
      xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4566
0
       "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4567
0
       value, attr->name, elem->name);
4568
0
      ret = 0;
4569
0
  }
4570
0
    }
4571
4572
    /* Fixed Attribute Default */
4573
0
    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4574
0
        (!xmlStrEqual(attrDecl->defaultValue, value))) {
4575
0
  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4576
0
     "Value for attribute %s of %s must be \"%s\"\n",
4577
0
         attr->name, elem->name, attrDecl->defaultValue);
4578
0
        ret = 0;
4579
0
    }
4580
4581
    /* Extra check for the attribute value */
4582
0
    ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4583
0
              attrDecl->atype, value);
4584
4585
0
    return(ret);
4586
0
}
4587
4588
/**
4589
 * xmlValidateOneNamespace:
4590
 * @ctxt:  the validation context
4591
 * @doc:  a document instance
4592
 * @elem:  an element instance
4593
 * @prefix:  the namespace prefix
4594
 * @ns:  an namespace declaration instance
4595
 * @value:  the attribute value (without entities processing)
4596
 *
4597
 * Try to validate a single namespace declaration for an element
4598
 * basically it does the following checks as described by the
4599
 * XML-1.0 recommendation:
4600
 *  - [ VC: Attribute Value Type ]
4601
 *  - [ VC: Fixed Attribute Default ]
4602
 *  - [ VC: Entity Name ]
4603
 *  - [ VC: Name Token ]
4604
 *  - [ VC: ID ]
4605
 *  - [ VC: IDREF ]
4606
 *  - [ VC: Entity Name ]
4607
 *  - [ VC: Notation Attributes ]
4608
 *
4609
 * The ID/IDREF uniqueness and matching are done separately
4610
 *
4611
 * returns 1 if valid or 0 otherwise
4612
 */
4613
4614
int
4615
xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4616
0
xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4617
    /* xmlElementPtr elemDecl; */
4618
0
    xmlAttributePtr attrDecl =  NULL;
4619
0
    int val;
4620
0
    int ret = 1;
4621
4622
0
    CHECK_DTD;
4623
0
    if ((elem == NULL) || (elem->name == NULL)) return(0);
4624
0
    if ((ns == NULL) || (ns->href == NULL)) return(0);
4625
4626
0
    if (prefix != NULL) {
4627
0
  xmlChar fn[50];
4628
0
  xmlChar *fullname;
4629
4630
0
  fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4631
0
  if (fullname == NULL) {
4632
0
      xmlVErrMemory(ctxt, "Validating namespace");
4633
0
      return(0);
4634
0
  }
4635
0
  if (ns->prefix != NULL) {
4636
0
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4637
0
                              ns->prefix, BAD_CAST "xmlns");
4638
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4639
0
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4640
0
            ns->prefix, BAD_CAST "xmlns");
4641
0
  } else {
4642
0
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4643
0
                             BAD_CAST "xmlns");
4644
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4645
0
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4646
0
                       BAD_CAST "xmlns");
4647
0
  }
4648
0
  if ((fullname != fn) && (fullname != elem->name))
4649
0
      xmlFree(fullname);
4650
0
    }
4651
0
    if (attrDecl == NULL) {
4652
0
  if (ns->prefix != NULL) {
4653
0
      attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4654
0
                              ns->prefix, BAD_CAST "xmlns");
4655
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4656
0
    attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4657
0
                ns->prefix, BAD_CAST "xmlns");
4658
0
  } else {
4659
0
      attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4660
0
                             elem->name, BAD_CAST "xmlns");
4661
0
      if ((attrDecl == NULL) && (doc->extSubset != NULL))
4662
0
    attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4663
0
               elem->name, BAD_CAST "xmlns");
4664
0
  }
4665
0
    }
4666
4667
4668
    /* Validity Constraint: Attribute Value Type */
4669
0
    if (attrDecl == NULL) {
4670
0
  if (ns->prefix != NULL) {
4671
0
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4672
0
       "No declaration for attribute xmlns:%s of element %s\n",
4673
0
       ns->prefix, elem->name, NULL);
4674
0
  } else {
4675
0
      xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4676
0
       "No declaration for attribute xmlns of element %s\n",
4677
0
       elem->name, NULL, NULL);
4678
0
  }
4679
0
  return(0);
4680
0
    }
4681
4682
0
    val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4683
0
    if (val == 0) {
4684
0
  if (ns->prefix != NULL) {
4685
0
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4686
0
         "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4687
0
       ns->prefix, elem->name, NULL);
4688
0
  } else {
4689
0
      xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4690
0
         "Syntax of value for attribute xmlns of %s is not valid\n",
4691
0
       elem->name, NULL, NULL);
4692
0
  }
4693
0
        ret = 0;
4694
0
    }
4695
4696
    /* Validity constraint: Fixed Attribute Default */
4697
0
    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4698
0
  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4699
0
      if (ns->prefix != NULL) {
4700
0
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4701
0
       "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4702
0
           ns->prefix, elem->name, attrDecl->defaultValue);
4703
0
      } else {
4704
0
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4705
0
       "Value for attribute xmlns of %s is different from default \"%s\"\n",
4706
0
           elem->name, attrDecl->defaultValue, NULL);
4707
0
      }
4708
0
      ret = 0;
4709
0
  }
4710
0
    }
4711
4712
    /*
4713
     * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4714
     * xmlAddID and xmlAddRef for namespace declarations, but it makes
4715
     * no practical sense to use ID types anyway.
4716
     */
4717
#if 0
4718
    /* Validity Constraint: ID uniqueness */
4719
    if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4720
        if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4721
      ret = 0;
4722
    }
4723
4724
    if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4725
  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4726
        if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4727
      ret = 0;
4728
    }
4729
#endif
4730
4731
    /* Validity Constraint: Notation Attributes */
4732
0
    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4733
0
        xmlEnumerationPtr tree = attrDecl->tree;
4734
0
        xmlNotationPtr nota;
4735
4736
        /* First check that the given NOTATION was declared */
4737
0
  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4738
0
  if (nota == NULL)
4739
0
      nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4740
4741
0
  if (nota == NULL) {
4742
0
      if (ns->prefix != NULL) {
4743
0
    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4744
0
       "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4745
0
           value, ns->prefix, elem->name);
4746
0
      } else {
4747
0
    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4748
0
       "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4749
0
           value, elem->name, NULL);
4750
0
      }
4751
0
      ret = 0;
4752
0
        }
4753
4754
  /* Second, verify that it's among the list */
4755
0
  while (tree != NULL) {
4756
0
      if (xmlStrEqual(tree->name, value)) break;
4757
0
      tree = tree->next;
4758
0
  }
4759
0
  if (tree == NULL) {
4760
0
      if (ns->prefix != NULL) {
4761
0
    xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4762
0
"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4763
0
           value, ns->prefix, elem->name);
4764
0
      } else {
4765
0
    xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4766
0
"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4767
0
           value, elem->name, NULL);
4768
0
      }
4769
0
      ret = 0;
4770
0
  }
4771
0
    }
4772
4773
    /* Validity Constraint: Enumeration */
4774
0
    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4775
0
        xmlEnumerationPtr tree = attrDecl->tree;
4776
0
  while (tree != NULL) {
4777
0
      if (xmlStrEqual(tree->name, value)) break;
4778
0
      tree = tree->next;
4779
0
  }
4780
0
  if (tree == NULL) {
4781
0
      if (ns->prefix != NULL) {
4782
0
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4783
0
"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4784
0
           value, ns->prefix, elem->name);
4785
0
      } else {
4786
0
    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4787
0
"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4788
0
           value, elem->name, NULL);
4789
0
      }
4790
0
      ret = 0;
4791
0
  }
4792
0
    }
4793
4794
    /* Fixed Attribute Default */
4795
0
    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4796
0
        (!xmlStrEqual(attrDecl->defaultValue, value))) {
4797
0
  if (ns->prefix != NULL) {
4798
0
      xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4799
0
       "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4800
0
       ns->prefix, elem->name, attrDecl->defaultValue);
4801
0
  } else {
4802
0
      xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4803
0
       "Value for attribute xmlns of %s must be \"%s\"\n",
4804
0
       elem->name, attrDecl->defaultValue, NULL);
4805
0
  }
4806
0
        ret = 0;
4807
0
    }
4808
4809
    /* Extra check for the attribute value */
4810
0
    if (ns->prefix != NULL) {
4811
0
  ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4812
0
            attrDecl->atype, value);
4813
0
    } else {
4814
0
  ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4815
0
            attrDecl->atype, value);
4816
0
    }
4817
4818
0
    return(ret);
4819
0
}
4820
4821
#ifndef  LIBXML_REGEXP_ENABLED
4822
/**
4823
 * xmlValidateSkipIgnorable:
4824
 * @ctxt:  the validation context
4825
 * @child:  the child list
4826
 *
4827
 * Skip ignorable elements w.r.t. the validation process
4828
 *
4829
 * returns the first element to consider for validation of the content model
4830
 */
4831
4832
static xmlNodePtr
4833
xmlValidateSkipIgnorable(xmlNodePtr child) {
4834
    while (child != NULL) {
4835
  switch (child->type) {
4836
      /* These things are ignored (skipped) during validation.  */
4837
      case XML_PI_NODE:
4838
      case XML_COMMENT_NODE:
4839
      case XML_XINCLUDE_START:
4840
      case XML_XINCLUDE_END:
4841
    child = child->next;
4842
    break;
4843
      case XML_TEXT_NODE:
4844
    if (xmlIsBlankNode(child))
4845
        child = child->next;
4846
    else
4847
        return(child);
4848
    break;
4849
      /* keep current node */
4850
      default:
4851
    return(child);
4852
  }
4853
    }
4854
    return(child);
4855
}
4856
4857
/**
4858
 * xmlValidateElementType:
4859
 * @ctxt:  the validation context
4860
 *
4861
 * Try to validate the