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