Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/xml2/relaxng.c
4389 views
1
/*
2
* relaxng.c : implementation of the Relax-NG handling and validity checking
3
*
4
* See Copyright for the status of this software.
5
*
6
* Daniel Veillard <[email protected]>
7
*/
8
9
/**
10
* TODO:
11
* - add support for DTD compatibility spec
12
* http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
13
* - report better mem allocations pbms at runtime and abort immediately.
14
*/
15
16
#define IN_LIBXML
17
#include "libxml.h"
18
19
#ifdef LIBXML_SCHEMAS_ENABLED
20
21
#include <string.h>
22
#include <stdio.h>
23
#include <stddef.h>
24
#include <libxml/xmlmemory.h>
25
#include <libxml/parser.h>
26
#include <libxml/parserInternals.h>
27
#include <libxml/hash.h>
28
#include <libxml/uri.h>
29
30
#include <libxml/relaxng.h>
31
32
#include <libxml/xmlschemastypes.h>
33
#include <libxml/xmlautomata.h>
34
#include <libxml/xmlregexp.h>
35
#include <libxml/xmlschemastypes.h>
36
37
#include "private/error.h"
38
#include "private/regexp.h"
39
#include "private/string.h"
40
41
/*
42
* The Relax-NG namespace
43
*/
44
static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
45
"http://relaxng.org/ns/structure/1.0";
46
47
#define IS_RELAXNG(node, typ) \
48
((node != NULL) && (node->ns != NULL) && \
49
(node->type == XML_ELEMENT_NODE) && \
50
(xmlStrEqual(node->name, (const xmlChar *) typ)) && \
51
(xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
52
53
54
#define MAX_ERROR 5
55
56
#define TODO \
57
xmlGenericError(xmlGenericErrorContext, \
58
"Unimplemented block at %s:%d\n", \
59
__FILE__, __LINE__);
60
61
typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
62
typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
63
64
typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
65
typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
66
67
typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
68
typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
69
70
typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
71
typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
72
73
typedef enum {
74
XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
75
XML_RELAXNG_COMBINE_CHOICE, /* choice */
76
XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
77
} xmlRelaxNGCombine;
78
79
typedef enum {
80
XML_RELAXNG_CONTENT_ERROR = -1,
81
XML_RELAXNG_CONTENT_EMPTY = 0,
82
XML_RELAXNG_CONTENT_SIMPLE,
83
XML_RELAXNG_CONTENT_COMPLEX
84
} xmlRelaxNGContentType;
85
86
typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
87
typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
88
89
struct _xmlRelaxNGGrammar {
90
xmlRelaxNGGrammarPtr parent; /* the parent grammar if any */
91
xmlRelaxNGGrammarPtr children; /* the children grammar if any */
92
xmlRelaxNGGrammarPtr next; /* the next grammar if any */
93
xmlRelaxNGDefinePtr start; /* <start> content */
94
xmlRelaxNGCombine combine; /* the default combine value */
95
xmlRelaxNGDefinePtr startList; /* list of <start> definitions */
96
xmlHashTablePtr defs; /* define* */
97
xmlHashTablePtr refs; /* references */
98
};
99
100
101
typedef enum {
102
XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
103
XML_RELAXNG_EMPTY = 0, /* an empty pattern */
104
XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
105
XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
106
XML_RELAXNG_TEXT, /* textual content */
107
XML_RELAXNG_ELEMENT, /* an element */
108
XML_RELAXNG_DATATYPE, /* external data type definition */
109
XML_RELAXNG_PARAM, /* external data type parameter */
110
XML_RELAXNG_VALUE, /* value from an external data type definition */
111
XML_RELAXNG_LIST, /* a list of patterns */
112
XML_RELAXNG_ATTRIBUTE, /* an attribute following a pattern */
113
XML_RELAXNG_DEF, /* a definition */
114
XML_RELAXNG_REF, /* reference to a definition */
115
XML_RELAXNG_EXTERNALREF, /* reference to an external def */
116
XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
117
XML_RELAXNG_OPTIONAL, /* optional patterns */
118
XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
119
XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
120
XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
121
XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
122
XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
123
XML_RELAXNG_START /* Used to keep track of starts on grammars */
124
} xmlRelaxNGType;
125
126
#define IS_NULLABLE (1 << 0)
127
#define IS_NOT_NULLABLE (1 << 1)
128
#define IS_INDETERMINIST (1 << 2)
129
#define IS_MIXED (1 << 3)
130
#define IS_TRIABLE (1 << 4)
131
#define IS_PROCESSED (1 << 5)
132
#define IS_COMPILABLE (1 << 6)
133
#define IS_NOT_COMPILABLE (1 << 7)
134
#define IS_EXTERNAL_REF (1 << 8)
135
136
struct _xmlRelaxNGDefine {
137
xmlRelaxNGType type; /* the type of definition */
138
xmlNodePtr node; /* the node in the source */
139
xmlChar *name; /* the element local name if present */
140
xmlChar *ns; /* the namespace local name if present */
141
xmlChar *value; /* value when available */
142
void *data; /* data lib or specific pointer */
143
xmlRelaxNGDefinePtr content; /* the expected content */
144
xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
145
xmlRelaxNGDefinePtr next; /* list within grouping sequences */
146
xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
147
xmlRelaxNGDefinePtr nameClass; /* the nameClass definition if any */
148
xmlRelaxNGDefinePtr nextHash; /* next define in defs/refs hash tables */
149
short depth; /* used for the cycle detection */
150
short dflags; /* define related flags */
151
xmlRegexpPtr contModel; /* a compiled content model if available */
152
};
153
154
/**
155
* _xmlRelaxNG:
156
*
157
* A RelaxNGs definition
158
*/
159
struct _xmlRelaxNG {
160
void *_private; /* unused by the library for users or bindings */
161
xmlRelaxNGGrammarPtr topgrammar;
162
xmlDocPtr doc;
163
164
int idref; /* requires idref checking */
165
166
xmlHashTablePtr defs; /* define */
167
xmlHashTablePtr refs; /* references */
168
xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
169
xmlRelaxNGIncludePtr includes; /* all the includes loaded */
170
int defNr; /* number of defines used */
171
xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
172
173
};
174
175
#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
176
#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
177
#define XML_RELAXNG_IN_LIST (1 << 2)
178
#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
179
#define XML_RELAXNG_IN_START (1 << 4)
180
#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
181
#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
182
#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
183
#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
184
#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
185
186
struct _xmlRelaxNGParserCtxt {
187
void *userData; /* user specific data block */
188
xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
189
xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
190
xmlStructuredErrorFunc serror;
191
xmlRelaxNGValidErr err;
192
193
xmlRelaxNGPtr schema; /* The schema in use */
194
xmlRelaxNGGrammarPtr grammar; /* the current grammar */
195
xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
196
int flags; /* parser flags */
197
int nbErrors; /* number of errors at parse time */
198
int nbWarnings; /* number of warnings at parse time */
199
const xmlChar *define; /* the current define scope */
200
xmlRelaxNGDefinePtr def; /* the current define */
201
202
int nbInterleaves;
203
xmlHashTablePtr interleaves; /* keep track of all the interleaves */
204
205
xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
206
xmlRelaxNGIncludePtr includes; /* all the includes loaded */
207
xmlChar *URL;
208
xmlDocPtr document;
209
210
int defNr; /* number of defines used */
211
int defMax; /* number of defines allocated */
212
xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
213
214
const char *buffer;
215
int size;
216
217
/* the document stack */
218
xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
219
int docNr; /* Depth of the parsing stack */
220
int docMax; /* Max depth of the parsing stack */
221
xmlRelaxNGDocumentPtr *docTab; /* array of docs */
222
223
/* the include stack */
224
xmlRelaxNGIncludePtr inc; /* Current parsed include */
225
int incNr; /* Depth of the include parsing stack */
226
int incMax; /* Max depth of the parsing stack */
227
xmlRelaxNGIncludePtr *incTab; /* array of incs */
228
229
int idref; /* requires idref checking */
230
231
/* used to compile content models */
232
xmlAutomataPtr am; /* the automata */
233
xmlAutomataStatePtr state; /* used to build the automata */
234
235
int crng; /* compact syntax and other flags */
236
int freedoc; /* need to free the document */
237
};
238
239
#define FLAGS_IGNORABLE 1
240
#define FLAGS_NEGATIVE 2
241
#define FLAGS_MIXED_CONTENT 4
242
#define FLAGS_NOERROR 8
243
244
/**
245
* xmlRelaxNGInterleaveGroup:
246
*
247
* A RelaxNGs partition set associated to lists of definitions
248
*/
249
typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
250
typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
251
struct _xmlRelaxNGInterleaveGroup {
252
xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
253
xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
254
xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
255
};
256
257
#define IS_DETERMINIST 1
258
#define IS_NEEDCHECK 2
259
260
/**
261
* xmlRelaxNGPartitions:
262
*
263
* A RelaxNGs partition associated to an interleave group
264
*/
265
typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
266
typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
267
struct _xmlRelaxNGPartition {
268
int nbgroups; /* number of groups in the partitions */
269
xmlHashTablePtr triage; /* hash table used to direct nodes to the
270
* right group when possible */
271
int flags; /* determinist ? */
272
xmlRelaxNGInterleaveGroupPtr *groups;
273
};
274
275
/**
276
* xmlRelaxNGValidState:
277
*
278
* A RelaxNGs validation state
279
*/
280
#define MAX_ATTR 20
281
typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
282
typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
283
struct _xmlRelaxNGValidState {
284
xmlNodePtr node; /* the current node */
285
xmlNodePtr seq; /* the sequence of children left to validate */
286
int nbAttrs; /* the number of attributes */
287
int maxAttrs; /* the size of attrs */
288
int nbAttrLeft; /* the number of attributes left to validate */
289
xmlChar *value; /* the value when operating on string */
290
xmlChar *endvalue; /* the end value when operating on string */
291
xmlAttrPtr *attrs; /* the array of attributes */
292
};
293
294
/**
295
* xmlRelaxNGStates:
296
*
297
* A RelaxNGs container for validation state
298
*/
299
typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
300
typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
301
struct _xmlRelaxNGStates {
302
int nbState; /* the number of states */
303
int maxState; /* the size of the array */
304
xmlRelaxNGValidStatePtr *tabState;
305
};
306
307
#define ERROR_IS_DUP 1
308
309
/**
310
* xmlRelaxNGValidError:
311
*
312
* A RelaxNGs validation error
313
*/
314
typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
315
typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
316
struct _xmlRelaxNGValidError {
317
xmlRelaxNGValidErr err; /* the error number */
318
int flags; /* flags */
319
xmlNodePtr node; /* the current node */
320
xmlNodePtr seq; /* the current child */
321
const xmlChar *arg1; /* first arg */
322
const xmlChar *arg2; /* second arg */
323
};
324
325
/**
326
* xmlRelaxNGValidCtxt:
327
*
328
* A RelaxNGs validation context
329
*/
330
331
struct _xmlRelaxNGValidCtxt {
332
void *userData; /* user specific data block */
333
xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
334
xmlRelaxNGValidityWarningFunc warning; /* the callback in case of warning */
335
xmlStructuredErrorFunc serror;
336
int nbErrors; /* number of errors in validation */
337
338
xmlRelaxNGPtr schema; /* The schema in use */
339
xmlDocPtr doc; /* the document being validated */
340
int flags; /* validation flags */
341
int depth; /* validation depth */
342
int idref; /* requires idref checking */
343
int errNo; /* the first error found */
344
345
/*
346
* Errors accumulated in branches may have to be stacked to be
347
* provided back when it's sure they affect validation.
348
*/
349
xmlRelaxNGValidErrorPtr err; /* Last error */
350
int errNr; /* Depth of the error stack */
351
int errMax; /* Max depth of the error stack */
352
xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
353
354
xmlRelaxNGValidStatePtr state; /* the current validation state */
355
xmlRelaxNGStatesPtr states; /* the accumulated state list */
356
357
xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
358
int freeStatesNr;
359
int freeStatesMax;
360
xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
361
362
/*
363
* This is used for "progressive" validation
364
*/
365
xmlRegExecCtxtPtr elem; /* the current element regexp */
366
int elemNr; /* the number of element validated */
367
int elemMax; /* the max depth of elements */
368
xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
369
int pstate; /* progressive state */
370
xmlNodePtr pnode; /* the current node */
371
xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
372
int perr; /* signal error in content model
373
* outside the regexp */
374
};
375
376
/**
377
* xmlRelaxNGInclude:
378
*
379
* Structure associated to a RelaxNGs document element
380
*/
381
struct _xmlRelaxNGInclude {
382
xmlRelaxNGIncludePtr next; /* keep a chain of includes */
383
xmlChar *href; /* the normalized href value */
384
xmlDocPtr doc; /* the associated XML document */
385
xmlRelaxNGDefinePtr content; /* the definitions */
386
xmlRelaxNGPtr schema; /* the schema */
387
};
388
389
/**
390
* xmlRelaxNGDocument:
391
*
392
* Structure associated to a RelaxNGs document element
393
*/
394
struct _xmlRelaxNGDocument {
395
xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
396
xmlChar *href; /* the normalized href value */
397
xmlDocPtr doc; /* the associated XML document */
398
xmlRelaxNGDefinePtr content; /* the definitions */
399
xmlRelaxNGPtr schema; /* the schema */
400
int externalRef; /* 1 if an external ref */
401
};
402
403
404
/************************************************************************
405
* *
406
* Some factorized error routines *
407
* *
408
************************************************************************/
409
410
/**
411
* xmlRngPErrMemory:
412
* @ctxt: an Relax-NG parser context
413
* @extra: extra information
414
*
415
* Handle a redefinition of attribute error
416
*/
417
static void
418
xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
419
{
420
xmlStructuredErrorFunc schannel = NULL;
421
xmlGenericErrorFunc channel = NULL;
422
void *data = NULL;
423
424
if (ctxt != NULL) {
425
if (ctxt->serror != NULL)
426
schannel = ctxt->serror;
427
else
428
channel = ctxt->error;
429
data = ctxt->userData;
430
ctxt->nbErrors++;
431
}
432
if (extra)
433
__xmlRaiseError(schannel, channel, data,
434
NULL, NULL, XML_FROM_RELAXNGP,
435
XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
436
NULL, NULL, 0, 0,
437
"Memory allocation failed : %s\n", extra);
438
else
439
__xmlRaiseError(schannel, channel, data,
440
NULL, NULL, XML_FROM_RELAXNGP,
441
XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
442
NULL, NULL, 0, 0, "Memory allocation failed\n");
443
}
444
445
/**
446
* xmlRngVErrMemory:
447
* @ctxt: a Relax-NG validation context
448
* @extra: extra information
449
*
450
* Handle a redefinition of attribute error
451
*/
452
static void
453
xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
454
{
455
xmlStructuredErrorFunc schannel = NULL;
456
xmlGenericErrorFunc channel = NULL;
457
void *data = NULL;
458
459
if (ctxt != NULL) {
460
if (ctxt->serror != NULL)
461
schannel = ctxt->serror;
462
else
463
channel = ctxt->error;
464
data = ctxt->userData;
465
ctxt->nbErrors++;
466
}
467
if (extra)
468
__xmlRaiseError(schannel, channel, data,
469
NULL, NULL, XML_FROM_RELAXNGV,
470
XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
471
NULL, NULL, 0, 0,
472
"Memory allocation failed : %s\n", extra);
473
else
474
__xmlRaiseError(schannel, channel, data,
475
NULL, NULL, XML_FROM_RELAXNGV,
476
XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
477
NULL, NULL, 0, 0, "Memory allocation failed\n");
478
}
479
480
/**
481
* xmlRngPErr:
482
* @ctxt: a Relax-NG parser context
483
* @node: the node raising the error
484
* @error: the error code
485
* @msg: message
486
* @str1: extra info
487
* @str2: extra info
488
*
489
* Handle a Relax NG Parsing error
490
*/
491
static void LIBXML_ATTR_FORMAT(4,0)
492
xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
493
const char *msg, const xmlChar * str1, const xmlChar * str2)
494
{
495
xmlStructuredErrorFunc schannel = NULL;
496
xmlGenericErrorFunc channel = NULL;
497
void *data = NULL;
498
499
if (ctxt != NULL) {
500
if (ctxt->serror != NULL)
501
schannel = ctxt->serror;
502
else
503
channel = ctxt->error;
504
data = ctxt->userData;
505
ctxt->nbErrors++;
506
}
507
__xmlRaiseError(schannel, channel, data,
508
NULL, node, XML_FROM_RELAXNGP,
509
error, XML_ERR_ERROR, NULL, 0,
510
(const char *) str1, (const char *) str2, NULL, 0, 0,
511
msg, str1, str2);
512
}
513
514
/**
515
* xmlRngVErr:
516
* @ctxt: a Relax-NG validation context
517
* @node: the node raising the error
518
* @error: the error code
519
* @msg: message
520
* @str1: extra info
521
* @str2: extra info
522
*
523
* Handle a Relax NG Validation error
524
*/
525
static void LIBXML_ATTR_FORMAT(4,0)
526
xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
527
const char *msg, const xmlChar * str1, const xmlChar * str2)
528
{
529
xmlStructuredErrorFunc schannel = NULL;
530
xmlGenericErrorFunc channel = NULL;
531
void *data = NULL;
532
533
if (ctxt != NULL) {
534
if (ctxt->serror != NULL)
535
schannel = ctxt->serror;
536
else
537
channel = ctxt->error;
538
data = ctxt->userData;
539
ctxt->nbErrors++;
540
}
541
__xmlRaiseError(schannel, channel, data,
542
NULL, node, XML_FROM_RELAXNGV,
543
error, XML_ERR_ERROR, NULL, 0,
544
(const char *) str1, (const char *) str2, NULL, 0, 0,
545
msg, str1, str2);
546
}
547
548
/************************************************************************
549
* *
550
* Preliminary type checking interfaces *
551
* *
552
************************************************************************/
553
554
/**
555
* xmlRelaxNGTypeHave:
556
* @data: data needed for the library
557
* @type: the type name
558
* @value: the value to check
559
*
560
* Function provided by a type library to check if a type is exported
561
*
562
* Returns 1 if yes, 0 if no and -1 in case of error.
563
*/
564
typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
565
566
/**
567
* xmlRelaxNGTypeCheck:
568
* @data: data needed for the library
569
* @type: the type name
570
* @value: the value to check
571
* @result: place to store the result if needed
572
*
573
* Function provided by a type library to check if a value match a type
574
*
575
* Returns 1 if yes, 0 if no and -1 in case of error.
576
*/
577
typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
578
const xmlChar * value, void **result,
579
xmlNodePtr node);
580
581
/**
582
* xmlRelaxNGFacetCheck:
583
* @data: data needed for the library
584
* @type: the type name
585
* @facet: the facet name
586
* @val: the facet value
587
* @strval: the string value
588
* @value: the value to check
589
*
590
* Function provided by a type library to check a value facet
591
*
592
* Returns 1 if yes, 0 if no and -1 in case of error.
593
*/
594
typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
595
const xmlChar * facet,
596
const xmlChar * val,
597
const xmlChar * strval, void *value);
598
599
/**
600
* xmlRelaxNGTypeFree:
601
* @data: data needed for the library
602
* @result: the value to free
603
*
604
* Function provided by a type library to free a returned result
605
*/
606
typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
607
608
/**
609
* xmlRelaxNGTypeCompare:
610
* @data: data needed for the library
611
* @type: the type name
612
* @value1: the first value
613
* @value2: the second value
614
*
615
* Function provided by a type library to compare two values accordingly
616
* to a type.
617
*
618
* Returns 1 if yes, 0 if no and -1 in case of error.
619
*/
620
typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
621
const xmlChar * value1,
622
xmlNodePtr ctxt1,
623
void *comp1,
624
const xmlChar * value2,
625
xmlNodePtr ctxt2);
626
typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
627
typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
628
struct _xmlRelaxNGTypeLibrary {
629
const xmlChar *namespace; /* the datatypeLibrary value */
630
void *data; /* data needed for the library */
631
xmlRelaxNGTypeHave have; /* the export function */
632
xmlRelaxNGTypeCheck check; /* the checking function */
633
xmlRelaxNGTypeCompare comp; /* the compare function */
634
xmlRelaxNGFacetCheck facet; /* the facet check function */
635
xmlRelaxNGTypeFree freef; /* the freeing function */
636
};
637
638
/************************************************************************
639
* *
640
* Allocation functions *
641
* *
642
************************************************************************/
643
static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
644
static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
645
static void xmlRelaxNGNormExtSpace(xmlChar * value);
646
static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
647
static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
648
ATTRIBUTE_UNUSED,
649
xmlRelaxNGValidStatePtr state1,
650
xmlRelaxNGValidStatePtr state2);
651
static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
652
xmlRelaxNGValidStatePtr state);
653
654
/**
655
* xmlRelaxNGFreeDocument:
656
* @docu: a document structure
657
*
658
* Deallocate a RelaxNG document structure.
659
*/
660
static void
661
xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
662
{
663
if (docu == NULL)
664
return;
665
666
if (docu->href != NULL)
667
xmlFree(docu->href);
668
if (docu->doc != NULL)
669
xmlFreeDoc(docu->doc);
670
if (docu->schema != NULL)
671
xmlRelaxNGFreeInnerSchema(docu->schema);
672
xmlFree(docu);
673
}
674
675
/**
676
* xmlRelaxNGFreeDocumentList:
677
* @docu: a list of document structure
678
*
679
* Deallocate a RelaxNG document structures.
680
*/
681
static void
682
xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
683
{
684
xmlRelaxNGDocumentPtr next;
685
686
while (docu != NULL) {
687
next = docu->next;
688
xmlRelaxNGFreeDocument(docu);
689
docu = next;
690
}
691
}
692
693
/**
694
* xmlRelaxNGFreeInclude:
695
* @incl: a include structure
696
*
697
* Deallocate a RelaxNG include structure.
698
*/
699
static void
700
xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
701
{
702
if (incl == NULL)
703
return;
704
705
if (incl->href != NULL)
706
xmlFree(incl->href);
707
if (incl->doc != NULL)
708
xmlFreeDoc(incl->doc);
709
if (incl->schema != NULL)
710
xmlRelaxNGFree(incl->schema);
711
xmlFree(incl);
712
}
713
714
/**
715
* xmlRelaxNGFreeIncludeList:
716
* @incl: a include structure list
717
*
718
* Deallocate a RelaxNG include structure.
719
*/
720
static void
721
xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
722
{
723
xmlRelaxNGIncludePtr next;
724
725
while (incl != NULL) {
726
next = incl->next;
727
xmlRelaxNGFreeInclude(incl);
728
incl = next;
729
}
730
}
731
732
/**
733
* xmlRelaxNGNewRelaxNG:
734
* @ctxt: a Relax-NG validation context (optional)
735
*
736
* Allocate a new RelaxNG structure.
737
*
738
* Returns the newly allocated structure or NULL in case or error
739
*/
740
static xmlRelaxNGPtr
741
xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
742
{
743
xmlRelaxNGPtr ret;
744
745
ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
746
if (ret == NULL) {
747
xmlRngPErrMemory(ctxt, NULL);
748
return (NULL);
749
}
750
memset(ret, 0, sizeof(xmlRelaxNG));
751
752
return (ret);
753
}
754
755
/**
756
* xmlRelaxNGFreeInnerSchema:
757
* @schema: a schema structure
758
*
759
* Deallocate a RelaxNG schema structure.
760
*/
761
static void
762
xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
763
{
764
if (schema == NULL)
765
return;
766
767
if (schema->doc != NULL)
768
xmlFreeDoc(schema->doc);
769
if (schema->defTab != NULL) {
770
int i;
771
772
for (i = 0; i < schema->defNr; i++)
773
xmlRelaxNGFreeDefine(schema->defTab[i]);
774
xmlFree(schema->defTab);
775
}
776
777
xmlFree(schema);
778
}
779
780
/**
781
* xmlRelaxNGFree:
782
* @schema: a schema structure
783
*
784
* Deallocate a RelaxNG structure.
785
*/
786
void
787
xmlRelaxNGFree(xmlRelaxNGPtr schema)
788
{
789
if (schema == NULL)
790
return;
791
792
if (schema->topgrammar != NULL)
793
xmlRelaxNGFreeGrammar(schema->topgrammar);
794
if (schema->doc != NULL)
795
xmlFreeDoc(schema->doc);
796
if (schema->documents != NULL)
797
xmlRelaxNGFreeDocumentList(schema->documents);
798
if (schema->includes != NULL)
799
xmlRelaxNGFreeIncludeList(schema->includes);
800
if (schema->defTab != NULL) {
801
int i;
802
803
for (i = 0; i < schema->defNr; i++)
804
xmlRelaxNGFreeDefine(schema->defTab[i]);
805
xmlFree(schema->defTab);
806
}
807
808
xmlFree(schema);
809
}
810
811
/**
812
* xmlRelaxNGNewGrammar:
813
* @ctxt: a Relax-NG validation context (optional)
814
*
815
* Allocate a new RelaxNG grammar.
816
*
817
* Returns the newly allocated structure or NULL in case or error
818
*/
819
static xmlRelaxNGGrammarPtr
820
xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
821
{
822
xmlRelaxNGGrammarPtr ret;
823
824
ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
825
if (ret == NULL) {
826
xmlRngPErrMemory(ctxt, NULL);
827
return (NULL);
828
}
829
memset(ret, 0, sizeof(xmlRelaxNGGrammar));
830
831
return (ret);
832
}
833
834
/**
835
* xmlRelaxNGFreeGrammar:
836
* @grammar: a grammar structure
837
*
838
* Deallocate a RelaxNG grammar structure.
839
*/
840
static void
841
xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
842
{
843
if (grammar == NULL)
844
return;
845
846
if (grammar->children != NULL) {
847
xmlRelaxNGFreeGrammar(grammar->children);
848
}
849
if (grammar->next != NULL) {
850
xmlRelaxNGFreeGrammar(grammar->next);
851
}
852
if (grammar->refs != NULL) {
853
xmlHashFree(grammar->refs, NULL);
854
}
855
if (grammar->defs != NULL) {
856
xmlHashFree(grammar->defs, NULL);
857
}
858
859
xmlFree(grammar);
860
}
861
862
/**
863
* xmlRelaxNGNewDefine:
864
* @ctxt: a Relax-NG validation context
865
* @node: the node in the input document.
866
*
867
* Allocate a new RelaxNG define.
868
*
869
* Returns the newly allocated structure or NULL in case or error
870
*/
871
static xmlRelaxNGDefinePtr
872
xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
873
{
874
xmlRelaxNGDefinePtr ret;
875
876
if (ctxt->defMax == 0) {
877
ctxt->defMax = 16;
878
ctxt->defNr = 0;
879
ctxt->defTab = (xmlRelaxNGDefinePtr *)
880
xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
881
if (ctxt->defTab == NULL) {
882
xmlRngPErrMemory(ctxt, "allocating define\n");
883
return (NULL);
884
}
885
} else if (ctxt->defMax <= ctxt->defNr) {
886
xmlRelaxNGDefinePtr *tmp;
887
888
ctxt->defMax *= 2;
889
tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
890
ctxt->defMax *
891
sizeof
892
(xmlRelaxNGDefinePtr));
893
if (tmp == NULL) {
894
xmlRngPErrMemory(ctxt, "allocating define\n");
895
return (NULL);
896
}
897
ctxt->defTab = tmp;
898
}
899
ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
900
if (ret == NULL) {
901
xmlRngPErrMemory(ctxt, "allocating define\n");
902
return (NULL);
903
}
904
memset(ret, 0, sizeof(xmlRelaxNGDefine));
905
ctxt->defTab[ctxt->defNr++] = ret;
906
ret->node = node;
907
ret->depth = -1;
908
return (ret);
909
}
910
911
/**
912
* xmlRelaxNGFreePartition:
913
* @partitions: a partition set structure
914
*
915
* Deallocate RelaxNG partition set structures.
916
*/
917
static void
918
xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
919
{
920
xmlRelaxNGInterleaveGroupPtr group;
921
int j;
922
923
if (partitions != NULL) {
924
if (partitions->groups != NULL) {
925
for (j = 0; j < partitions->nbgroups; j++) {
926
group = partitions->groups[j];
927
if (group != NULL) {
928
if (group->defs != NULL)
929
xmlFree(group->defs);
930
if (group->attrs != NULL)
931
xmlFree(group->attrs);
932
xmlFree(group);
933
}
934
}
935
xmlFree(partitions->groups);
936
}
937
if (partitions->triage != NULL) {
938
xmlHashFree(partitions->triage, NULL);
939
}
940
xmlFree(partitions);
941
}
942
}
943
944
/**
945
* xmlRelaxNGFreeDefine:
946
* @define: a define structure
947
*
948
* Deallocate a RelaxNG define structure.
949
*/
950
static void
951
xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
952
{
953
if (define == NULL)
954
return;
955
956
if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
957
xmlRelaxNGTypeLibraryPtr lib;
958
959
lib = (xmlRelaxNGTypeLibraryPtr) define->data;
960
if ((lib != NULL) && (lib->freef != NULL))
961
lib->freef(lib->data, (void *) define->attrs);
962
}
963
if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
964
xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
965
if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
966
xmlHashFree((xmlHashTablePtr) define->data, NULL);
967
if (define->name != NULL)
968
xmlFree(define->name);
969
if (define->ns != NULL)
970
xmlFree(define->ns);
971
if (define->value != NULL)
972
xmlFree(define->value);
973
if (define->contModel != NULL)
974
xmlRegFreeRegexp(define->contModel);
975
xmlFree(define);
976
}
977
978
/**
979
* xmlRelaxNGNewStates:
980
* @ctxt: a Relax-NG validation context
981
* @size: the default size for the container
982
*
983
* Allocate a new RelaxNG validation state container
984
*
985
* Returns the newly allocated structure or NULL in case or error
986
*/
987
static xmlRelaxNGStatesPtr
988
xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
989
{
990
xmlRelaxNGStatesPtr ret;
991
992
if ((ctxt != NULL) &&
993
(ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
994
ctxt->freeStatesNr--;
995
ret = ctxt->freeStates[ctxt->freeStatesNr];
996
ret->nbState = 0;
997
return (ret);
998
}
999
if (size < 16)
1000
size = 16;
1001
1002
ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
1003
(size -
1004
1) *
1005
sizeof(xmlRelaxNGValidStatePtr));
1006
if (ret == NULL) {
1007
xmlRngVErrMemory(ctxt, "allocating states\n");
1008
return (NULL);
1009
}
1010
ret->nbState = 0;
1011
ret->maxState = size;
1012
ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1013
sizeof
1014
(xmlRelaxNGValidStatePtr));
1015
if (ret->tabState == NULL) {
1016
xmlRngVErrMemory(ctxt, "allocating states\n");
1017
xmlFree(ret);
1018
return (NULL);
1019
}
1020
return (ret);
1021
}
1022
1023
/**
1024
* xmlRelaxNGAddStateUniq:
1025
* @ctxt: a Relax-NG validation context
1026
* @states: the states container
1027
* @state: the validation state
1028
*
1029
* Add a RelaxNG validation state to the container without checking
1030
* for unicity.
1031
*
1032
* Return 1 in case of success and 0 if this is a duplicate and -1 on error
1033
*/
1034
static int
1035
xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
1036
xmlRelaxNGStatesPtr states,
1037
xmlRelaxNGValidStatePtr state)
1038
{
1039
if (state == NULL) {
1040
return (-1);
1041
}
1042
if (states->nbState >= states->maxState) {
1043
xmlRelaxNGValidStatePtr *tmp;
1044
int size;
1045
1046
size = states->maxState * 2;
1047
tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1048
(size) *
1049
sizeof
1050
(xmlRelaxNGValidStatePtr));
1051
if (tmp == NULL) {
1052
xmlRngVErrMemory(ctxt, "adding states\n");
1053
return (-1);
1054
}
1055
states->tabState = tmp;
1056
states->maxState = size;
1057
}
1058
states->tabState[states->nbState++] = state;
1059
return (1);
1060
}
1061
1062
/**
1063
* xmlRelaxNGAddState:
1064
* @ctxt: a Relax-NG validation context
1065
* @states: the states container
1066
* @state: the validation state
1067
*
1068
* Add a RelaxNG validation state to the container
1069
*
1070
* Return 1 in case of success and 0 if this is a duplicate and -1 on error
1071
*/
1072
static int
1073
xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1074
xmlRelaxNGStatesPtr states,
1075
xmlRelaxNGValidStatePtr state)
1076
{
1077
int i;
1078
1079
if (state == NULL || states == NULL) {
1080
return (-1);
1081
}
1082
if (states->nbState >= states->maxState) {
1083
xmlRelaxNGValidStatePtr *tmp;
1084
int size;
1085
1086
size = states->maxState * 2;
1087
tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1088
(size) *
1089
sizeof
1090
(xmlRelaxNGValidStatePtr));
1091
if (tmp == NULL) {
1092
xmlRngVErrMemory(ctxt, "adding states\n");
1093
return (-1);
1094
}
1095
states->tabState = tmp;
1096
states->maxState = size;
1097
}
1098
for (i = 0; i < states->nbState; i++) {
1099
if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1100
xmlRelaxNGFreeValidState(ctxt, state);
1101
return (0);
1102
}
1103
}
1104
states->tabState[states->nbState++] = state;
1105
return (1);
1106
}
1107
1108
/**
1109
* xmlRelaxNGFreeStates:
1110
* @ctxt: a Relax-NG validation context
1111
* @states: the container
1112
*
1113
* Free a RelaxNG validation state container
1114
*/
1115
static void
1116
xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
1117
xmlRelaxNGStatesPtr states)
1118
{
1119
if (states == NULL)
1120
return;
1121
if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
1122
ctxt->freeStatesMax = 40;
1123
ctxt->freeStatesNr = 0;
1124
ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1125
xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1126
if (ctxt->freeStates == NULL) {
1127
xmlRngVErrMemory(ctxt, "storing states\n");
1128
}
1129
} else if ((ctxt != NULL)
1130
&& (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1131
xmlRelaxNGStatesPtr *tmp;
1132
1133
tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1134
2 * ctxt->freeStatesMax *
1135
sizeof
1136
(xmlRelaxNGStatesPtr));
1137
if (tmp == NULL) {
1138
xmlRngVErrMemory(ctxt, "storing states\n");
1139
xmlFree(states->tabState);
1140
xmlFree(states);
1141
return;
1142
}
1143
ctxt->freeStates = tmp;
1144
ctxt->freeStatesMax *= 2;
1145
}
1146
if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
1147
xmlFree(states->tabState);
1148
xmlFree(states);
1149
} else {
1150
ctxt->freeStates[ctxt->freeStatesNr++] = states;
1151
}
1152
}
1153
1154
/**
1155
* xmlRelaxNGNewValidState:
1156
* @ctxt: a Relax-NG validation context
1157
* @node: the current node or NULL for the document
1158
*
1159
* Allocate a new RelaxNG validation state
1160
*
1161
* Returns the newly allocated structure or NULL in case or error
1162
*/
1163
static xmlRelaxNGValidStatePtr
1164
xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1165
{
1166
xmlRelaxNGValidStatePtr ret;
1167
xmlAttrPtr attr;
1168
xmlAttrPtr attrs[MAX_ATTR];
1169
int nbAttrs = 0;
1170
xmlNodePtr root = NULL;
1171
1172
if (node == NULL) {
1173
root = xmlDocGetRootElement(ctxt->doc);
1174
if (root == NULL)
1175
return (NULL);
1176
} else {
1177
attr = node->properties;
1178
while (attr != NULL) {
1179
if (nbAttrs < MAX_ATTR)
1180
attrs[nbAttrs++] = attr;
1181
else
1182
nbAttrs++;
1183
attr = attr->next;
1184
}
1185
}
1186
if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1187
ctxt->freeState->nbState--;
1188
ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1189
} else {
1190
ret =
1191
(xmlRelaxNGValidStatePtr)
1192
xmlMalloc(sizeof(xmlRelaxNGValidState));
1193
if (ret == NULL) {
1194
xmlRngVErrMemory(ctxt, "allocating states\n");
1195
return (NULL);
1196
}
1197
memset(ret, 0, sizeof(xmlRelaxNGValidState));
1198
}
1199
ret->value = NULL;
1200
ret->endvalue = NULL;
1201
if (node == NULL) {
1202
ret->node = (xmlNodePtr) ctxt->doc;
1203
ret->seq = root;
1204
} else {
1205
ret->node = node;
1206
ret->seq = node->children;
1207
}
1208
ret->nbAttrs = 0;
1209
if (nbAttrs > 0) {
1210
if (ret->attrs == NULL) {
1211
if (nbAttrs < 4)
1212
ret->maxAttrs = 4;
1213
else
1214
ret->maxAttrs = nbAttrs;
1215
ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1216
sizeof(xmlAttrPtr));
1217
if (ret->attrs == NULL) {
1218
xmlRngVErrMemory(ctxt, "allocating states\n");
1219
return (ret);
1220
}
1221
} else if (ret->maxAttrs < nbAttrs) {
1222
xmlAttrPtr *tmp;
1223
1224
tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1225
sizeof(xmlAttrPtr));
1226
if (tmp == NULL) {
1227
xmlRngVErrMemory(ctxt, "allocating states\n");
1228
return (ret);
1229
}
1230
ret->attrs = tmp;
1231
ret->maxAttrs = nbAttrs;
1232
}
1233
ret->nbAttrs = nbAttrs;
1234
if (nbAttrs < MAX_ATTR) {
1235
memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1236
} else {
1237
attr = node->properties;
1238
nbAttrs = 0;
1239
while (attr != NULL) {
1240
ret->attrs[nbAttrs++] = attr;
1241
attr = attr->next;
1242
}
1243
}
1244
}
1245
ret->nbAttrLeft = ret->nbAttrs;
1246
return (ret);
1247
}
1248
1249
/**
1250
* xmlRelaxNGCopyValidState:
1251
* @ctxt: a Relax-NG validation context
1252
* @state: a validation state
1253
*
1254
* Copy the validation state
1255
*
1256
* Returns the newly allocated structure or NULL in case or error
1257
*/
1258
static xmlRelaxNGValidStatePtr
1259
xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1260
xmlRelaxNGValidStatePtr state)
1261
{
1262
xmlRelaxNGValidStatePtr ret;
1263
unsigned int maxAttrs;
1264
xmlAttrPtr *attrs;
1265
1266
if (state == NULL)
1267
return (NULL);
1268
if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1269
ctxt->freeState->nbState--;
1270
ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1271
} else {
1272
ret =
1273
(xmlRelaxNGValidStatePtr)
1274
xmlMalloc(sizeof(xmlRelaxNGValidState));
1275
if (ret == NULL) {
1276
xmlRngVErrMemory(ctxt, "allocating states\n");
1277
return (NULL);
1278
}
1279
memset(ret, 0, sizeof(xmlRelaxNGValidState));
1280
}
1281
attrs = ret->attrs;
1282
maxAttrs = ret->maxAttrs;
1283
memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1284
ret->attrs = attrs;
1285
ret->maxAttrs = maxAttrs;
1286
if (state->nbAttrs > 0) {
1287
if (ret->attrs == NULL) {
1288
ret->maxAttrs = state->maxAttrs;
1289
ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1290
sizeof(xmlAttrPtr));
1291
if (ret->attrs == NULL) {
1292
xmlRngVErrMemory(ctxt, "allocating states\n");
1293
ret->nbAttrs = 0;
1294
return (ret);
1295
}
1296
} else if (ret->maxAttrs < state->nbAttrs) {
1297
xmlAttrPtr *tmp;
1298
1299
tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1300
sizeof(xmlAttrPtr));
1301
if (tmp == NULL) {
1302
xmlRngVErrMemory(ctxt, "allocating states\n");
1303
ret->nbAttrs = 0;
1304
return (ret);
1305
}
1306
ret->maxAttrs = state->maxAttrs;
1307
ret->attrs = tmp;
1308
}
1309
memcpy(ret->attrs, state->attrs,
1310
state->nbAttrs * sizeof(xmlAttrPtr));
1311
}
1312
return (ret);
1313
}
1314
1315
/**
1316
* xmlRelaxNGEqualValidState:
1317
* @ctxt: a Relax-NG validation context
1318
* @state1: a validation state
1319
* @state2: a validation state
1320
*
1321
* Compare the validation states for equality
1322
*
1323
* Returns 1 if equal, 0 otherwise
1324
*/
1325
static int
1326
xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1327
xmlRelaxNGValidStatePtr state1,
1328
xmlRelaxNGValidStatePtr state2)
1329
{
1330
int i;
1331
1332
if ((state1 == NULL) || (state2 == NULL))
1333
return (0);
1334
if (state1 == state2)
1335
return (1);
1336
if (state1->node != state2->node)
1337
return (0);
1338
if (state1->seq != state2->seq)
1339
return (0);
1340
if (state1->nbAttrLeft != state2->nbAttrLeft)
1341
return (0);
1342
if (state1->nbAttrs != state2->nbAttrs)
1343
return (0);
1344
if (state1->endvalue != state2->endvalue)
1345
return (0);
1346
if ((state1->value != state2->value) &&
1347
(!xmlStrEqual(state1->value, state2->value)))
1348
return (0);
1349
for (i = 0; i < state1->nbAttrs; i++) {
1350
if (state1->attrs[i] != state2->attrs[i])
1351
return (0);
1352
}
1353
return (1);
1354
}
1355
1356
/**
1357
* xmlRelaxNGFreeValidState:
1358
* @state: a validation state structure
1359
*
1360
* Deallocate a RelaxNG validation state structure.
1361
*/
1362
static void
1363
xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1364
xmlRelaxNGValidStatePtr state)
1365
{
1366
if (state == NULL)
1367
return;
1368
1369
if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1370
ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1371
}
1372
if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1373
if (state->attrs != NULL)
1374
xmlFree(state->attrs);
1375
xmlFree(state);
1376
} else {
1377
xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1378
}
1379
}
1380
1381
/************************************************************************
1382
* *
1383
* Semi internal functions *
1384
* *
1385
************************************************************************/
1386
1387
/**
1388
* xmlRelaxParserSetFlag:
1389
* @ctxt: a RelaxNG parser context
1390
* @flags: a set of flags values
1391
*
1392
* Semi private function used to pass information to a parser context
1393
* which are a combination of xmlRelaxNGParserFlag .
1394
*
1395
* Returns 0 if success and -1 in case of error
1396
*/
1397
int
1398
xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1399
{
1400
if (ctxt == NULL) return(-1);
1401
if (flags & XML_RELAXNGP_FREE_DOC) {
1402
ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1403
flags -= XML_RELAXNGP_FREE_DOC;
1404
}
1405
if (flags & XML_RELAXNGP_CRNG) {
1406
ctxt->crng |= XML_RELAXNGP_CRNG;
1407
flags -= XML_RELAXNGP_CRNG;
1408
}
1409
if (flags != 0) return(-1);
1410
return(0);
1411
}
1412
1413
/************************************************************************
1414
* *
1415
* Document functions *
1416
* *
1417
************************************************************************/
1418
static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1419
xmlDocPtr doc);
1420
1421
/**
1422
* xmlRelaxNGIncludePush:
1423
* @ctxt: the parser context
1424
* @value: the element doc
1425
*
1426
* Pushes a new include on top of the include stack
1427
*
1428
* Returns 0 in case of error, the index in the stack otherwise
1429
*/
1430
static int
1431
xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1432
xmlRelaxNGIncludePtr value)
1433
{
1434
if (ctxt->incTab == NULL) {
1435
ctxt->incMax = 4;
1436
ctxt->incNr = 0;
1437
ctxt->incTab =
1438
(xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1439
sizeof(ctxt->incTab[0]));
1440
if (ctxt->incTab == NULL) {
1441
xmlRngPErrMemory(ctxt, "allocating include\n");
1442
return (0);
1443
}
1444
}
1445
if (ctxt->incNr >= ctxt->incMax) {
1446
ctxt->incMax *= 2;
1447
ctxt->incTab =
1448
(xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1449
ctxt->incMax *
1450
sizeof(ctxt->incTab[0]));
1451
if (ctxt->incTab == NULL) {
1452
xmlRngPErrMemory(ctxt, "allocating include\n");
1453
return (0);
1454
}
1455
}
1456
ctxt->incTab[ctxt->incNr] = value;
1457
ctxt->inc = value;
1458
return (ctxt->incNr++);
1459
}
1460
1461
/**
1462
* xmlRelaxNGIncludePop:
1463
* @ctxt: the parser context
1464
*
1465
* Pops the top include from the include stack
1466
*
1467
* Returns the include just removed
1468
*/
1469
static xmlRelaxNGIncludePtr
1470
xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1471
{
1472
xmlRelaxNGIncludePtr ret;
1473
1474
if (ctxt->incNr <= 0)
1475
return (NULL);
1476
ctxt->incNr--;
1477
if (ctxt->incNr > 0)
1478
ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1479
else
1480
ctxt->inc = NULL;
1481
ret = ctxt->incTab[ctxt->incNr];
1482
ctxt->incTab[ctxt->incNr] = NULL;
1483
return (ret);
1484
}
1485
1486
/**
1487
* xmlRelaxNGRemoveRedefine:
1488
* @ctxt: the parser context
1489
* @URL: the normalized URL
1490
* @target: the included target
1491
* @name: the define name to eliminate
1492
*
1493
* Applies the elimination algorithm of 4.7
1494
*
1495
* Returns 0 in case of error, 1 in case of success.
1496
*/
1497
static int
1498
xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1499
const xmlChar * URL ATTRIBUTE_UNUSED,
1500
xmlNodePtr target, const xmlChar * name)
1501
{
1502
int found = 0;
1503
xmlNodePtr tmp, tmp2;
1504
xmlChar *name2;
1505
1506
tmp = target;
1507
while (tmp != NULL) {
1508
tmp2 = tmp->next;
1509
if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1510
found = 1;
1511
xmlUnlinkNode(tmp);
1512
xmlFreeNode(tmp);
1513
} else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1514
name2 = xmlGetProp(tmp, BAD_CAST "name");
1515
xmlRelaxNGNormExtSpace(name2);
1516
if (name2 != NULL) {
1517
if (xmlStrEqual(name, name2)) {
1518
found = 1;
1519
xmlUnlinkNode(tmp);
1520
xmlFreeNode(tmp);
1521
}
1522
xmlFree(name2);
1523
}
1524
} else if (IS_RELAXNG(tmp, "include")) {
1525
xmlChar *href = NULL;
1526
xmlRelaxNGDocumentPtr inc = tmp->psvi;
1527
1528
if ((inc != NULL) && (inc->doc != NULL) &&
1529
(inc->doc->children != NULL)) {
1530
1531
if (xmlStrEqual
1532
(inc->doc->children->name, BAD_CAST "grammar")) {
1533
if (xmlRelaxNGRemoveRedefine(ctxt, href,
1534
xmlDocGetRootElement(inc->doc)->children,
1535
name) == 1) {
1536
found = 1;
1537
}
1538
}
1539
}
1540
if (xmlRelaxNGRemoveRedefine(ctxt, URL, tmp->children, name) == 1) {
1541
found = 1;
1542
}
1543
}
1544
tmp = tmp2;
1545
}
1546
return (found);
1547
}
1548
1549
/**
1550
* xmlRelaxNGLoadInclude:
1551
* @ctxt: the parser context
1552
* @URL: the normalized URL
1553
* @node: the include node.
1554
* @ns: the namespace passed from the context.
1555
*
1556
* First lookup if the document is already loaded into the parser context,
1557
* check against recursion. If not found the resource is loaded and
1558
* the content is preprocessed before being returned back to the caller.
1559
*
1560
* Returns the xmlRelaxNGIncludePtr or NULL in case of error
1561
*/
1562
static xmlRelaxNGIncludePtr
1563
xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1564
xmlNodePtr node, const xmlChar * ns)
1565
{
1566
xmlRelaxNGIncludePtr ret = NULL;
1567
xmlDocPtr doc;
1568
int i;
1569
xmlNodePtr root, cur;
1570
1571
/*
1572
* check against recursion in the stack
1573
*/
1574
for (i = 0; i < ctxt->incNr; i++) {
1575
if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1576
xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1577
"Detected an Include recursion for %s\n", URL,
1578
NULL);
1579
return (NULL);
1580
}
1581
}
1582
1583
/*
1584
* load the document
1585
*/
1586
doc = xmlReadFile((const char *) URL,NULL,0);
1587
if (doc == NULL) {
1588
xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1589
"xmlRelaxNG: could not load %s\n", URL, NULL);
1590
return (NULL);
1591
}
1592
1593
/*
1594
* Allocate the document structures and register it first.
1595
*/
1596
ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1597
if (ret == NULL) {
1598
xmlRngPErrMemory(ctxt, "allocating include\n");
1599
xmlFreeDoc(doc);
1600
return (NULL);
1601
}
1602
memset(ret, 0, sizeof(xmlRelaxNGInclude));
1603
ret->doc = doc;
1604
ret->href = xmlStrdup(URL);
1605
ret->next = ctxt->includes;
1606
ctxt->includes = ret;
1607
1608
/*
1609
* transmit the ns if needed
1610
*/
1611
if (ns != NULL) {
1612
root = xmlDocGetRootElement(doc);
1613
if (root != NULL) {
1614
if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1615
xmlSetProp(root, BAD_CAST "ns", ns);
1616
}
1617
}
1618
}
1619
1620
/*
1621
* push it on the stack
1622
*/
1623
xmlRelaxNGIncludePush(ctxt, ret);
1624
1625
/*
1626
* Some preprocessing of the document content, this include recursing
1627
* in the include stack.
1628
*/
1629
1630
doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1631
if (doc == NULL) {
1632
ctxt->inc = NULL;
1633
return (NULL);
1634
}
1635
1636
/*
1637
* Pop up the include from the stack
1638
*/
1639
xmlRelaxNGIncludePop(ctxt);
1640
1641
/*
1642
* Check that the top element is a grammar
1643
*/
1644
root = xmlDocGetRootElement(doc);
1645
if (root == NULL) {
1646
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1647
"xmlRelaxNG: included document is empty %s\n", URL,
1648
NULL);
1649
return (NULL);
1650
}
1651
if (!IS_RELAXNG(root, "grammar")) {
1652
xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1653
"xmlRelaxNG: included document %s root is not a grammar\n",
1654
URL, NULL);
1655
return (NULL);
1656
}
1657
1658
/*
1659
* Elimination of redefined rules in the include.
1660
*/
1661
cur = node->children;
1662
while (cur != NULL) {
1663
if (IS_RELAXNG(cur, "start")) {
1664
int found = 0;
1665
1666
found =
1667
xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1668
if (!found) {
1669
xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1670
"xmlRelaxNG: include %s has a start but not the included grammar\n",
1671
URL, NULL);
1672
}
1673
} else if (IS_RELAXNG(cur, "define")) {
1674
xmlChar *name;
1675
1676
name = xmlGetProp(cur, BAD_CAST "name");
1677
if (name == NULL) {
1678
xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1679
"xmlRelaxNG: include %s has define without name\n",
1680
URL, NULL);
1681
} else {
1682
int found;
1683
1684
xmlRelaxNGNormExtSpace(name);
1685
found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1686
root->children, name);
1687
if (!found) {
1688
xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1689
"xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1690
URL, name);
1691
}
1692
xmlFree(name);
1693
}
1694
}
1695
if (IS_RELAXNG(cur, "div") && cur->children != NULL) {
1696
cur = cur->children;
1697
} else {
1698
if (cur->next != NULL) {
1699
cur = cur->next;
1700
} else {
1701
while (cur->parent != node && cur->parent->next == NULL) {
1702
cur = cur->parent;
1703
}
1704
cur = cur->parent != node ? cur->parent->next : NULL;
1705
}
1706
}
1707
}
1708
1709
1710
return (ret);
1711
}
1712
1713
/**
1714
* xmlRelaxNGValidErrorPush:
1715
* @ctxt: the validation context
1716
* @err: the error code
1717
* @arg1: the first string argument
1718
* @arg2: the second string argument
1719
* @dup: arg need to be duplicated
1720
*
1721
* Pushes a new error on top of the error stack
1722
*
1723
* Returns 0 in case of error, the index in the stack otherwise
1724
*/
1725
static int
1726
xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1727
xmlRelaxNGValidErr err, const xmlChar * arg1,
1728
const xmlChar * arg2, int dup)
1729
{
1730
xmlRelaxNGValidErrorPtr cur;
1731
1732
if (ctxt->errTab == NULL) {
1733
ctxt->errMax = 8;
1734
ctxt->errNr = 0;
1735
ctxt->errTab =
1736
(xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1737
sizeof
1738
(xmlRelaxNGValidError));
1739
if (ctxt->errTab == NULL) {
1740
xmlRngVErrMemory(ctxt, "pushing error\n");
1741
return (0);
1742
}
1743
ctxt->err = NULL;
1744
}
1745
if (ctxt->errNr >= ctxt->errMax) {
1746
ctxt->errMax *= 2;
1747
ctxt->errTab =
1748
(xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1749
ctxt->errMax *
1750
sizeof
1751
(xmlRelaxNGValidError));
1752
if (ctxt->errTab == NULL) {
1753
xmlRngVErrMemory(ctxt, "pushing error\n");
1754
return (0);
1755
}
1756
ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1757
}
1758
if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
1759
(ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1760
return (ctxt->errNr);
1761
cur = &ctxt->errTab[ctxt->errNr];
1762
cur->err = err;
1763
if (dup) {
1764
cur->arg1 = xmlStrdup(arg1);
1765
cur->arg2 = xmlStrdup(arg2);
1766
cur->flags = ERROR_IS_DUP;
1767
} else {
1768
cur->arg1 = arg1;
1769
cur->arg2 = arg2;
1770
cur->flags = 0;
1771
}
1772
if (ctxt->state != NULL) {
1773
cur->node = ctxt->state->node;
1774
cur->seq = ctxt->state->seq;
1775
} else {
1776
cur->node = NULL;
1777
cur->seq = NULL;
1778
}
1779
ctxt->err = cur;
1780
return (ctxt->errNr++);
1781
}
1782
1783
/**
1784
* xmlRelaxNGValidErrorPop:
1785
* @ctxt: the validation context
1786
*
1787
* Pops the top error from the error stack
1788
*/
1789
static void
1790
xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1791
{
1792
xmlRelaxNGValidErrorPtr cur;
1793
1794
if (ctxt->errNr <= 0) {
1795
ctxt->err = NULL;
1796
return;
1797
}
1798
ctxt->errNr--;
1799
if (ctxt->errNr > 0)
1800
ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1801
else
1802
ctxt->err = NULL;
1803
cur = &ctxt->errTab[ctxt->errNr];
1804
if (cur->flags & ERROR_IS_DUP) {
1805
if (cur->arg1 != NULL)
1806
xmlFree((xmlChar *) cur->arg1);
1807
cur->arg1 = NULL;
1808
if (cur->arg2 != NULL)
1809
xmlFree((xmlChar *) cur->arg2);
1810
cur->arg2 = NULL;
1811
cur->flags = 0;
1812
}
1813
}
1814
1815
/**
1816
* xmlRelaxNGDocumentPush:
1817
* @ctxt: the parser context
1818
* @value: the element doc
1819
*
1820
* Pushes a new doc on top of the doc stack
1821
*
1822
* Returns 0 in case of error, the index in the stack otherwise
1823
*/
1824
static int
1825
xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1826
xmlRelaxNGDocumentPtr value)
1827
{
1828
if (ctxt->docTab == NULL) {
1829
ctxt->docMax = 4;
1830
ctxt->docNr = 0;
1831
ctxt->docTab =
1832
(xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1833
sizeof(ctxt->docTab[0]));
1834
if (ctxt->docTab == NULL) {
1835
xmlRngPErrMemory(ctxt, "adding document\n");
1836
return (0);
1837
}
1838
}
1839
if (ctxt->docNr >= ctxt->docMax) {
1840
ctxt->docMax *= 2;
1841
ctxt->docTab =
1842
(xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1843
ctxt->docMax *
1844
sizeof(ctxt->docTab[0]));
1845
if (ctxt->docTab == NULL) {
1846
xmlRngPErrMemory(ctxt, "adding document\n");
1847
return (0);
1848
}
1849
}
1850
ctxt->docTab[ctxt->docNr] = value;
1851
ctxt->doc = value;
1852
return (ctxt->docNr++);
1853
}
1854
1855
/**
1856
* xmlRelaxNGDocumentPop:
1857
* @ctxt: the parser context
1858
*
1859
* Pops the top doc from the doc stack
1860
*
1861
* Returns the doc just removed
1862
*/
1863
static xmlRelaxNGDocumentPtr
1864
xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1865
{
1866
xmlRelaxNGDocumentPtr ret;
1867
1868
if (ctxt->docNr <= 0)
1869
return (NULL);
1870
ctxt->docNr--;
1871
if (ctxt->docNr > 0)
1872
ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1873
else
1874
ctxt->doc = NULL;
1875
ret = ctxt->docTab[ctxt->docNr];
1876
ctxt->docTab[ctxt->docNr] = NULL;
1877
return (ret);
1878
}
1879
1880
/**
1881
* xmlRelaxNGLoadExternalRef:
1882
* @ctxt: the parser context
1883
* @URL: the normalized URL
1884
* @ns: the inherited ns if any
1885
*
1886
* First lookup if the document is already loaded into the parser context,
1887
* check against recursion. If not found the resource is loaded and
1888
* the content is preprocessed before being returned back to the caller.
1889
*
1890
* Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1891
*/
1892
static xmlRelaxNGDocumentPtr
1893
xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1894
const xmlChar * URL, const xmlChar * ns)
1895
{
1896
xmlRelaxNGDocumentPtr ret = NULL;
1897
xmlDocPtr doc;
1898
xmlNodePtr root;
1899
int i;
1900
1901
/*
1902
* check against recursion in the stack
1903
*/
1904
for (i = 0; i < ctxt->docNr; i++) {
1905
if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1906
xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1907
"Detected an externalRef recursion for %s\n", URL,
1908
NULL);
1909
return (NULL);
1910
}
1911
}
1912
1913
/*
1914
* load the document
1915
*/
1916
doc = xmlReadFile((const char *) URL,NULL,0);
1917
if (doc == NULL) {
1918
xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1919
"xmlRelaxNG: could not load %s\n", URL, NULL);
1920
return (NULL);
1921
}
1922
1923
/*
1924
* Allocate the document structures and register it first.
1925
*/
1926
ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1927
if (ret == NULL) {
1928
xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1929
"xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1930
xmlFreeDoc(doc);
1931
return (NULL);
1932
}
1933
memset(ret, 0, sizeof(xmlRelaxNGDocument));
1934
ret->doc = doc;
1935
ret->href = xmlStrdup(URL);
1936
ret->next = ctxt->documents;
1937
ret->externalRef = 1;
1938
ctxt->documents = ret;
1939
1940
/*
1941
* transmit the ns if needed
1942
*/
1943
if (ns != NULL) {
1944
root = xmlDocGetRootElement(doc);
1945
if (root != NULL) {
1946
if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1947
xmlSetProp(root, BAD_CAST "ns", ns);
1948
}
1949
}
1950
}
1951
1952
/*
1953
* push it on the stack and register it in the hash table
1954
*/
1955
xmlRelaxNGDocumentPush(ctxt, ret);
1956
1957
/*
1958
* Some preprocessing of the document content
1959
*/
1960
doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1961
if (doc == NULL) {
1962
ctxt->doc = NULL;
1963
return (NULL);
1964
}
1965
1966
xmlRelaxNGDocumentPop(ctxt);
1967
1968
return (ret);
1969
}
1970
1971
/************************************************************************
1972
* *
1973
* Error functions *
1974
* *
1975
************************************************************************/
1976
1977
#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1978
#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1979
#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1980
#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1981
#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
1982
1983
static const char *
1984
xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
1985
{
1986
if (def == NULL)
1987
return ("none");
1988
switch (def->type) {
1989
case XML_RELAXNG_EMPTY:
1990
return ("empty");
1991
case XML_RELAXNG_NOT_ALLOWED:
1992
return ("notAllowed");
1993
case XML_RELAXNG_EXCEPT:
1994
return ("except");
1995
case XML_RELAXNG_TEXT:
1996
return ("text");
1997
case XML_RELAXNG_ELEMENT:
1998
return ("element");
1999
case XML_RELAXNG_DATATYPE:
2000
return ("datatype");
2001
case XML_RELAXNG_VALUE:
2002
return ("value");
2003
case XML_RELAXNG_LIST:
2004
return ("list");
2005
case XML_RELAXNG_ATTRIBUTE:
2006
return ("attribute");
2007
case XML_RELAXNG_DEF:
2008
return ("def");
2009
case XML_RELAXNG_REF:
2010
return ("ref");
2011
case XML_RELAXNG_EXTERNALREF:
2012
return ("externalRef");
2013
case XML_RELAXNG_PARENTREF:
2014
return ("parentRef");
2015
case XML_RELAXNG_OPTIONAL:
2016
return ("optional");
2017
case XML_RELAXNG_ZEROORMORE:
2018
return ("zeroOrMore");
2019
case XML_RELAXNG_ONEORMORE:
2020
return ("oneOrMore");
2021
case XML_RELAXNG_CHOICE:
2022
return ("choice");
2023
case XML_RELAXNG_GROUP:
2024
return ("group");
2025
case XML_RELAXNG_INTERLEAVE:
2026
return ("interleave");
2027
case XML_RELAXNG_START:
2028
return ("start");
2029
case XML_RELAXNG_NOOP:
2030
return ("noop");
2031
case XML_RELAXNG_PARAM:
2032
return ("param");
2033
}
2034
return ("unknown");
2035
}
2036
2037
/**
2038
* xmlRelaxNGGetErrorString:
2039
* @err: the error code
2040
* @arg1: the first string argument
2041
* @arg2: the second string argument
2042
*
2043
* computes a formatted error string for the given error code and args
2044
*
2045
* Returns the error string, it must be deallocated by the caller
2046
*/
2047
static xmlChar *
2048
xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2049
const xmlChar * arg2)
2050
{
2051
char msg[1000];
2052
xmlChar *result;
2053
2054
if (arg1 == NULL)
2055
arg1 = BAD_CAST "";
2056
if (arg2 == NULL)
2057
arg2 = BAD_CAST "";
2058
2059
msg[0] = 0;
2060
switch (err) {
2061
case XML_RELAXNG_OK:
2062
return (NULL);
2063
case XML_RELAXNG_ERR_MEMORY:
2064
return (xmlCharStrdup("out of memory\n"));
2065
case XML_RELAXNG_ERR_TYPE:
2066
snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2067
break;
2068
case XML_RELAXNG_ERR_TYPEVAL:
2069
snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2070
arg2);
2071
break;
2072
case XML_RELAXNG_ERR_DUPID:
2073
snprintf(msg, 1000, "ID %s redefined\n", arg1);
2074
break;
2075
case XML_RELAXNG_ERR_TYPECMP:
2076
snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2077
break;
2078
case XML_RELAXNG_ERR_NOSTATE:
2079
return (xmlCharStrdup("Internal error: no state\n"));
2080
case XML_RELAXNG_ERR_NODEFINE:
2081
return (xmlCharStrdup("Internal error: no define\n"));
2082
case XML_RELAXNG_ERR_INTERNAL:
2083
snprintf(msg, 1000, "Internal error: %s\n", arg1);
2084
break;
2085
case XML_RELAXNG_ERR_LISTEXTRA:
2086
snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2087
break;
2088
case XML_RELAXNG_ERR_INTERNODATA:
2089
return (xmlCharStrdup
2090
("Internal: interleave block has no data\n"));
2091
case XML_RELAXNG_ERR_INTERSEQ:
2092
return (xmlCharStrdup("Invalid sequence in interleave\n"));
2093
case XML_RELAXNG_ERR_INTEREXTRA:
2094
snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2095
break;
2096
case XML_RELAXNG_ERR_ELEMNAME:
2097
snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2098
arg2);
2099
break;
2100
case XML_RELAXNG_ERR_ELEMNONS:
2101
snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2102
arg1);
2103
break;
2104
case XML_RELAXNG_ERR_ELEMWRONGNS:
2105
snprintf(msg, 1000,
2106
"Element %s has wrong namespace: expecting %s\n", arg1,
2107
arg2);
2108
break;
2109
case XML_RELAXNG_ERR_ELEMWRONG:
2110
snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2111
break;
2112
case XML_RELAXNG_ERR_TEXTWRONG:
2113
snprintf(msg, 1000,
2114
"Did not expect text in element %s content\n", arg1);
2115
break;
2116
case XML_RELAXNG_ERR_ELEMEXTRANS:
2117
snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2118
arg1);
2119
break;
2120
case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2121
snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2122
break;
2123
case XML_RELAXNG_ERR_NOELEM:
2124
snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2125
arg1);
2126
break;
2127
case XML_RELAXNG_ERR_NOTELEM:
2128
return (xmlCharStrdup("Expecting an element got text\n"));
2129
case XML_RELAXNG_ERR_ATTRVALID:
2130
snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2131
arg1);
2132
break;
2133
case XML_RELAXNG_ERR_CONTENTVALID:
2134
snprintf(msg, 1000, "Element %s failed to validate content\n",
2135
arg1);
2136
break;
2137
case XML_RELAXNG_ERR_EXTRACONTENT:
2138
snprintf(msg, 1000, "Element %s has extra content: %s\n",
2139
arg1, arg2);
2140
break;
2141
case XML_RELAXNG_ERR_INVALIDATTR:
2142
snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2143
arg1, arg2);
2144
break;
2145
case XML_RELAXNG_ERR_LACKDATA:
2146
snprintf(msg, 1000, "Datatype element %s contains no data\n",
2147
arg1);
2148
break;
2149
case XML_RELAXNG_ERR_DATAELEM:
2150
snprintf(msg, 1000, "Datatype element %s has child elements\n",
2151
arg1);
2152
break;
2153
case XML_RELAXNG_ERR_VALELEM:
2154
snprintf(msg, 1000, "Value element %s has child elements\n",
2155
arg1);
2156
break;
2157
case XML_RELAXNG_ERR_LISTELEM:
2158
snprintf(msg, 1000, "List element %s has child elements\n",
2159
arg1);
2160
break;
2161
case XML_RELAXNG_ERR_DATATYPE:
2162
snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2163
break;
2164
case XML_RELAXNG_ERR_VALUE:
2165
snprintf(msg, 1000, "Error validating value %s\n", arg1);
2166
break;
2167
case XML_RELAXNG_ERR_LIST:
2168
return (xmlCharStrdup("Error validating list\n"));
2169
case XML_RELAXNG_ERR_NOGRAMMAR:
2170
return (xmlCharStrdup("No top grammar defined\n"));
2171
case XML_RELAXNG_ERR_EXTRADATA:
2172
return (xmlCharStrdup("Extra data in the document\n"));
2173
default:
2174
return (xmlCharStrdup("Unknown error !\n"));
2175
}
2176
if (msg[0] == 0) {
2177
snprintf(msg, 1000, "Unknown error code %d\n", err);
2178
}
2179
msg[1000 - 1] = 0;
2180
result = xmlCharStrdup(msg);
2181
return (xmlEscapeFormatString(&result));
2182
}
2183
2184
/**
2185
* xmlRelaxNGShowValidError:
2186
* @ctxt: the validation context
2187
* @err: the error number
2188
* @node: the node
2189
* @child: the node child generating the problem.
2190
* @arg1: the first argument
2191
* @arg2: the second argument
2192
*
2193
* Show a validation error.
2194
*/
2195
static void
2196
xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2197
xmlRelaxNGValidErr err, xmlNodePtr node,
2198
xmlNodePtr child, const xmlChar * arg1,
2199
const xmlChar * arg2)
2200
{
2201
xmlChar *msg;
2202
2203
if (ctxt->flags & FLAGS_NOERROR)
2204
return;
2205
2206
msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2207
if (msg == NULL)
2208
return;
2209
2210
if (ctxt->errNo == XML_RELAXNG_OK)
2211
ctxt->errNo = err;
2212
xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2213
(const char *) msg, arg1, arg2);
2214
xmlFree(msg);
2215
}
2216
2217
/**
2218
* xmlRelaxNGPopErrors:
2219
* @ctxt: the validation context
2220
* @level: the error level in the stack
2221
*
2222
* pop and discard all errors until the given level is reached
2223
*/
2224
static void
2225
xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2226
{
2227
int i;
2228
xmlRelaxNGValidErrorPtr err;
2229
2230
for (i = level; i < ctxt->errNr; i++) {
2231
err = &ctxt->errTab[i];
2232
if (err->flags & ERROR_IS_DUP) {
2233
if (err->arg1 != NULL)
2234
xmlFree((xmlChar *) err->arg1);
2235
err->arg1 = NULL;
2236
if (err->arg2 != NULL)
2237
xmlFree((xmlChar *) err->arg2);
2238
err->arg2 = NULL;
2239
err->flags = 0;
2240
}
2241
}
2242
ctxt->errNr = level;
2243
if (ctxt->errNr <= 0)
2244
ctxt->err = NULL;
2245
}
2246
2247
/**
2248
* xmlRelaxNGDumpValidError:
2249
* @ctxt: the validation context
2250
*
2251
* Show all validation error over a given index.
2252
*/
2253
static void
2254
xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2255
{
2256
int i, j, k;
2257
xmlRelaxNGValidErrorPtr err, dup;
2258
2259
for (i = 0, k = 0; i < ctxt->errNr; i++) {
2260
err = &ctxt->errTab[i];
2261
if (k < MAX_ERROR) {
2262
for (j = 0; j < i; j++) {
2263
dup = &ctxt->errTab[j];
2264
if ((err->err == dup->err) && (err->node == dup->node) &&
2265
(xmlStrEqual(err->arg1, dup->arg1)) &&
2266
(xmlStrEqual(err->arg2, dup->arg2))) {
2267
goto skip;
2268
}
2269
}
2270
xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2271
err->arg1, err->arg2);
2272
k++;
2273
}
2274
skip:
2275
if (err->flags & ERROR_IS_DUP) {
2276
if (err->arg1 != NULL)
2277
xmlFree((xmlChar *) err->arg1);
2278
err->arg1 = NULL;
2279
if (err->arg2 != NULL)
2280
xmlFree((xmlChar *) err->arg2);
2281
err->arg2 = NULL;
2282
err->flags = 0;
2283
}
2284
}
2285
ctxt->errNr = 0;
2286
}
2287
2288
/**
2289
* xmlRelaxNGAddValidError:
2290
* @ctxt: the validation context
2291
* @err: the error number
2292
* @arg1: the first argument
2293
* @arg2: the second argument
2294
* @dup: need to dup the args
2295
*
2296
* Register a validation error, either generating it if it's sure
2297
* or stacking it for later handling if unsure.
2298
*/
2299
static void
2300
xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2301
xmlRelaxNGValidErr err, const xmlChar * arg1,
2302
const xmlChar * arg2, int dup)
2303
{
2304
if (ctxt == NULL)
2305
return;
2306
if (ctxt->flags & FLAGS_NOERROR)
2307
return;
2308
2309
/*
2310
* generate the error directly
2311
*/
2312
if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2313
(ctxt->flags & FLAGS_NEGATIVE)) {
2314
xmlNodePtr node, seq;
2315
2316
/*
2317
* Flush first any stacked error which might be the
2318
* real cause of the problem.
2319
*/
2320
if (ctxt->errNr != 0)
2321
xmlRelaxNGDumpValidError(ctxt);
2322
if (ctxt->state != NULL) {
2323
node = ctxt->state->node;
2324
seq = ctxt->state->seq;
2325
} else {
2326
node = seq = NULL;
2327
}
2328
if ((node == NULL) && (seq == NULL)) {
2329
node = ctxt->pnode;
2330
}
2331
xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2332
}
2333
/*
2334
* Stack the error for later processing if needed
2335
*/
2336
else {
2337
xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
2338
}
2339
}
2340
2341
2342
/************************************************************************
2343
* *
2344
* Type library hooks *
2345
* *
2346
************************************************************************/
2347
static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2348
const xmlChar * str);
2349
2350
/**
2351
* xmlRelaxNGSchemaTypeHave:
2352
* @data: data needed for the library
2353
* @type: the type name
2354
*
2355
* Check if the given type is provided by
2356
* the W3C XMLSchema Datatype library.
2357
*
2358
* Returns 1 if yes, 0 if no and -1 in case of error.
2359
*/
2360
static int
2361
xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2362
{
2363
xmlSchemaTypePtr typ;
2364
2365
if (type == NULL)
2366
return (-1);
2367
typ = xmlSchemaGetPredefinedType(type,
2368
BAD_CAST
2369
"http://www.w3.org/2001/XMLSchema");
2370
if (typ == NULL)
2371
return (0);
2372
return (1);
2373
}
2374
2375
/**
2376
* xmlRelaxNGSchemaTypeCheck:
2377
* @data: data needed for the library
2378
* @type: the type name
2379
* @value: the value to check
2380
* @node: the node
2381
*
2382
* Check if the given type and value are validated by
2383
* the W3C XMLSchema Datatype library.
2384
*
2385
* Returns 1 if yes, 0 if no and -1 in case of error.
2386
*/
2387
static int
2388
xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
2389
const xmlChar * type,
2390
const xmlChar * value,
2391
void **result, xmlNodePtr node)
2392
{
2393
xmlSchemaTypePtr typ;
2394
int ret;
2395
2396
if ((type == NULL) || (value == NULL))
2397
return (-1);
2398
typ = xmlSchemaGetPredefinedType(type,
2399
BAD_CAST
2400
"http://www.w3.org/2001/XMLSchema");
2401
if (typ == NULL)
2402
return (-1);
2403
ret = xmlSchemaValPredefTypeNode(typ, value,
2404
(xmlSchemaValPtr *) result, node);
2405
if (ret == 2) /* special ID error code */
2406
return (2);
2407
if (ret == 0)
2408
return (1);
2409
if (ret > 0)
2410
return (0);
2411
return (-1);
2412
}
2413
2414
/**
2415
* xmlRelaxNGSchemaFacetCheck:
2416
* @data: data needed for the library
2417
* @type: the type name
2418
* @facet: the facet name
2419
* @val: the facet value
2420
* @strval: the string value
2421
* @value: the value to check
2422
*
2423
* Function provided by a type library to check a value facet
2424
*
2425
* Returns 1 if yes, 0 if no and -1 in case of error.
2426
*/
2427
static int
2428
xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2429
const xmlChar * type, const xmlChar * facetname,
2430
const xmlChar * val, const xmlChar * strval,
2431
void *value)
2432
{
2433
xmlSchemaFacetPtr facet;
2434
xmlSchemaTypePtr typ;
2435
int ret;
2436
2437
if ((type == NULL) || (strval == NULL))
2438
return (-1);
2439
typ = xmlSchemaGetPredefinedType(type,
2440
BAD_CAST
2441
"http://www.w3.org/2001/XMLSchema");
2442
if (typ == NULL)
2443
return (-1);
2444
2445
facet = xmlSchemaNewFacet();
2446
if (facet == NULL)
2447
return (-1);
2448
2449
if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2450
facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2451
} else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2452
facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2453
} else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2454
facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2455
} else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2456
facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2457
} else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2458
facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2459
} else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2460
facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2461
} else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2462
facet->type = XML_SCHEMA_FACET_PATTERN;
2463
} else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2464
facet->type = XML_SCHEMA_FACET_ENUMERATION;
2465
} else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2466
facet->type = XML_SCHEMA_FACET_WHITESPACE;
2467
} else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2468
facet->type = XML_SCHEMA_FACET_LENGTH;
2469
} else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2470
facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2471
} else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2472
facet->type = XML_SCHEMA_FACET_MINLENGTH;
2473
} else {
2474
xmlSchemaFreeFacet(facet);
2475
return (-1);
2476
}
2477
facet->value = val;
2478
ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2479
if (ret != 0) {
2480
xmlSchemaFreeFacet(facet);
2481
return (-1);
2482
}
2483
ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2484
xmlSchemaFreeFacet(facet);
2485
if (ret != 0)
2486
return (-1);
2487
return (0);
2488
}
2489
2490
/**
2491
* xmlRelaxNGSchemaFreeValue:
2492
* @data: data needed for the library
2493
* @value: the value to free
2494
*
2495
* Function provided by a type library to free a Schemas value
2496
*
2497
* Returns 1 if yes, 0 if no and -1 in case of error.
2498
*/
2499
static void
2500
xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2501
{
2502
xmlSchemaFreeValue(value);
2503
}
2504
2505
/**
2506
* xmlRelaxNGSchemaTypeCompare:
2507
* @data: data needed for the library
2508
* @type: the type name
2509
* @value1: the first value
2510
* @value2: the second value
2511
*
2512
* Compare two values for equality accordingly a type from the W3C XMLSchema
2513
* Datatype library.
2514
*
2515
* Returns 1 if equal, 0 if no and -1 in case of error.
2516
*/
2517
static int
2518
xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2519
const xmlChar * type,
2520
const xmlChar * value1,
2521
xmlNodePtr ctxt1,
2522
void *comp1,
2523
const xmlChar * value2, xmlNodePtr ctxt2)
2524
{
2525
int ret;
2526
xmlSchemaTypePtr typ;
2527
xmlSchemaValPtr res1 = NULL, res2 = NULL;
2528
2529
if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2530
return (-1);
2531
typ = xmlSchemaGetPredefinedType(type,
2532
BAD_CAST
2533
"http://www.w3.org/2001/XMLSchema");
2534
if (typ == NULL)
2535
return (-1);
2536
if (comp1 == NULL) {
2537
ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2538
if (ret != 0)
2539
return (-1);
2540
if (res1 == NULL)
2541
return (-1);
2542
} else {
2543
res1 = (xmlSchemaValPtr) comp1;
2544
}
2545
ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
2546
if (ret != 0) {
2547
if (res1 != (xmlSchemaValPtr) comp1)
2548
xmlSchemaFreeValue(res1);
2549
return (-1);
2550
}
2551
ret = xmlSchemaCompareValues(res1, res2);
2552
if (res1 != (xmlSchemaValPtr) comp1)
2553
xmlSchemaFreeValue(res1);
2554
xmlSchemaFreeValue(res2);
2555
if (ret == -2)
2556
return (-1);
2557
if (ret == 0)
2558
return (1);
2559
return (0);
2560
}
2561
2562
/**
2563
* xmlRelaxNGDefaultTypeHave:
2564
* @data: data needed for the library
2565
* @type: the type name
2566
*
2567
* Check if the given type is provided by
2568
* the default datatype library.
2569
*
2570
* Returns 1 if yes, 0 if no and -1 in case of error.
2571
*/
2572
static int
2573
xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2574
const xmlChar * type)
2575
{
2576
if (type == NULL)
2577
return (-1);
2578
if (xmlStrEqual(type, BAD_CAST "string"))
2579
return (1);
2580
if (xmlStrEqual(type, BAD_CAST "token"))
2581
return (1);
2582
return (0);
2583
}
2584
2585
/**
2586
* xmlRelaxNGDefaultTypeCheck:
2587
* @data: data needed for the library
2588
* @type: the type name
2589
* @value: the value to check
2590
* @node: the node
2591
*
2592
* Check if the given type and value are validated by
2593
* the default datatype library.
2594
*
2595
* Returns 1 if yes, 0 if no and -1 in case of error.
2596
*/
2597
static int
2598
xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2599
const xmlChar * type ATTRIBUTE_UNUSED,
2600
const xmlChar * value ATTRIBUTE_UNUSED,
2601
void **result ATTRIBUTE_UNUSED,
2602
xmlNodePtr node ATTRIBUTE_UNUSED)
2603
{
2604
if (value == NULL)
2605
return (-1);
2606
if (xmlStrEqual(type, BAD_CAST "string"))
2607
return (1);
2608
if (xmlStrEqual(type, BAD_CAST "token")) {
2609
return (1);
2610
}
2611
2612
return (0);
2613
}
2614
2615
/**
2616
* xmlRelaxNGDefaultTypeCompare:
2617
* @data: data needed for the library
2618
* @type: the type name
2619
* @value1: the first value
2620
* @value2: the second value
2621
*
2622
* Compare two values accordingly a type from the default
2623
* datatype library.
2624
*
2625
* Returns 1 if yes, 0 if no and -1 in case of error.
2626
*/
2627
static int
2628
xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2629
const xmlChar * type,
2630
const xmlChar * value1,
2631
xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2632
void *comp1 ATTRIBUTE_UNUSED,
2633
const xmlChar * value2,
2634
xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2635
{
2636
int ret = -1;
2637
2638
if (xmlStrEqual(type, BAD_CAST "string")) {
2639
ret = xmlStrEqual(value1, value2);
2640
} else if (xmlStrEqual(type, BAD_CAST "token")) {
2641
if (!xmlStrEqual(value1, value2)) {
2642
xmlChar *nval, *nvalue;
2643
2644
/*
2645
* TODO: trivial optimizations are possible by
2646
* computing at compile-time
2647
*/
2648
nval = xmlRelaxNGNormalize(NULL, value1);
2649
nvalue = xmlRelaxNGNormalize(NULL, value2);
2650
2651
if ((nval == NULL) || (nvalue == NULL))
2652
ret = -1;
2653
else if (xmlStrEqual(nval, nvalue))
2654
ret = 1;
2655
else
2656
ret = 0;
2657
if (nval != NULL)
2658
xmlFree(nval);
2659
if (nvalue != NULL)
2660
xmlFree(nvalue);
2661
} else
2662
ret = 1;
2663
}
2664
return (ret);
2665
}
2666
2667
static int xmlRelaxNGTypeInitialized = 0;
2668
static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2669
2670
/**
2671
* xmlRelaxNGFreeTypeLibrary:
2672
* @lib: the type library structure
2673
* @namespace: the URI bound to the library
2674
*
2675
* Free the structure associated to the type library
2676
*/
2677
static void
2678
xmlRelaxNGFreeTypeLibrary(void *payload,
2679
const xmlChar * namespace ATTRIBUTE_UNUSED)
2680
{
2681
xmlRelaxNGTypeLibraryPtr lib = (xmlRelaxNGTypeLibraryPtr) payload;
2682
if (lib == NULL)
2683
return;
2684
if (lib->namespace != NULL)
2685
xmlFree((xmlChar *) lib->namespace);
2686
xmlFree(lib);
2687
}
2688
2689
/**
2690
* xmlRelaxNGRegisterTypeLibrary:
2691
* @namespace: the URI bound to the library
2692
* @data: data associated to the library
2693
* @have: the provide function
2694
* @check: the checking function
2695
* @comp: the comparison function
2696
*
2697
* Register a new type library
2698
*
2699
* Returns 0 in case of success and -1 in case of error.
2700
*/
2701
static int
2702
xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2703
xmlRelaxNGTypeHave have,
2704
xmlRelaxNGTypeCheck check,
2705
xmlRelaxNGTypeCompare comp,
2706
xmlRelaxNGFacetCheck facet,
2707
xmlRelaxNGTypeFree freef)
2708
{
2709
xmlRelaxNGTypeLibraryPtr lib;
2710
int ret;
2711
2712
if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2713
(check == NULL) || (comp == NULL))
2714
return (-1);
2715
if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2716
xmlGenericError(xmlGenericErrorContext,
2717
"Relax-NG types library '%s' already registered\n",
2718
namespace);
2719
return (-1);
2720
}
2721
lib =
2722
(xmlRelaxNGTypeLibraryPtr)
2723
xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2724
if (lib == NULL) {
2725
xmlRngVErrMemory(NULL, "adding types library\n");
2726
return (-1);
2727
}
2728
memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2729
lib->namespace = xmlStrdup(namespace);
2730
lib->data = data;
2731
lib->have = have;
2732
lib->comp = comp;
2733
lib->check = check;
2734
lib->facet = facet;
2735
lib->freef = freef;
2736
ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2737
if (ret < 0) {
2738
xmlGenericError(xmlGenericErrorContext,
2739
"Relax-NG types library failed to register '%s'\n",
2740
namespace);
2741
xmlRelaxNGFreeTypeLibrary(lib, namespace);
2742
return (-1);
2743
}
2744
return (0);
2745
}
2746
2747
/**
2748
* xmlRelaxNGInitTypes:
2749
*
2750
* Initialize the default type libraries.
2751
*
2752
* Returns 0 in case of success and -1 in case of error.
2753
*/
2754
int
2755
xmlRelaxNGInitTypes(void)
2756
{
2757
if (xmlRelaxNGTypeInitialized != 0)
2758
return (0);
2759
xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2760
if (xmlRelaxNGRegisteredTypes == NULL) {
2761
xmlGenericError(xmlGenericErrorContext,
2762
"Failed to allocate sh table for Relax-NG types\n");
2763
return (-1);
2764
}
2765
xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2766
"http://www.w3.org/2001/XMLSchema-datatypes",
2767
NULL, xmlRelaxNGSchemaTypeHave,
2768
xmlRelaxNGSchemaTypeCheck,
2769
xmlRelaxNGSchemaTypeCompare,
2770
xmlRelaxNGSchemaFacetCheck,
2771
xmlRelaxNGSchemaFreeValue);
2772
xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2773
xmlRelaxNGDefaultTypeHave,
2774
xmlRelaxNGDefaultTypeCheck,
2775
xmlRelaxNGDefaultTypeCompare, NULL,
2776
NULL);
2777
xmlRelaxNGTypeInitialized = 1;
2778
return (0);
2779
}
2780
2781
/**
2782
* xmlRelaxNGCleanupTypes:
2783
*
2784
* DEPRECATED: This function will be made private. Call xmlCleanupParser
2785
* to free global state but see the warnings there. xmlCleanupParser
2786
* should be only called once at program exit. In most cases, you don't
2787
* have call cleanup functions at all.
2788
*
2789
* Cleanup the default Schemas type library associated to RelaxNG
2790
*/
2791
void
2792
xmlRelaxNGCleanupTypes(void)
2793
{
2794
xmlSchemaCleanupTypes();
2795
if (xmlRelaxNGTypeInitialized == 0)
2796
return;
2797
xmlHashFree(xmlRelaxNGRegisteredTypes, xmlRelaxNGFreeTypeLibrary);
2798
xmlRelaxNGTypeInitialized = 0;
2799
}
2800
2801
/************************************************************************
2802
* *
2803
* Compiling element content into regexp *
2804
* *
2805
* Sometime the element content can be compiled into a pure regexp, *
2806
* This allows a faster execution and streamability at that level *
2807
* *
2808
************************************************************************/
2809
2810
static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2811
xmlRelaxNGDefinePtr def);
2812
2813
/**
2814
* xmlRelaxNGIsCompilable:
2815
* @define: the definition to check
2816
*
2817
* Check if a definition is nullable.
2818
*
2819
* Returns 1 if yes, 0 if no and -1 in case of error
2820
*/
2821
static int
2822
xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def)
2823
{
2824
int ret = -1;
2825
2826
if (def == NULL) {
2827
return (-1);
2828
}
2829
if ((def->type != XML_RELAXNG_ELEMENT) &&
2830
(def->dflags & IS_COMPILABLE))
2831
return (1);
2832
if ((def->type != XML_RELAXNG_ELEMENT) &&
2833
(def->dflags & IS_NOT_COMPILABLE))
2834
return (0);
2835
switch (def->type) {
2836
case XML_RELAXNG_NOOP:
2837
ret = xmlRelaxNGIsCompilable(def->content);
2838
break;
2839
case XML_RELAXNG_TEXT:
2840
case XML_RELAXNG_EMPTY:
2841
ret = 1;
2842
break;
2843
case XML_RELAXNG_ELEMENT:
2844
/*
2845
* Check if the element content is compilable
2846
*/
2847
if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2848
((def->dflags & IS_COMPILABLE) == 0)) {
2849
xmlRelaxNGDefinePtr list;
2850
2851
list = def->content;
2852
while (list != NULL) {
2853
ret = xmlRelaxNGIsCompilable(list);
2854
if (ret != 1)
2855
break;
2856
list = list->next;
2857
}
2858
/*
2859
* Because the routine is recursive, we must guard against
2860
* discovering both COMPILABLE and NOT_COMPILABLE
2861
*/
2862
if (ret == 0) {
2863
def->dflags &= ~IS_COMPILABLE;
2864
def->dflags |= IS_NOT_COMPILABLE;
2865
}
2866
if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
2867
def->dflags |= IS_COMPILABLE;
2868
}
2869
/*
2870
* All elements return a compilable status unless they
2871
* are generic like anyName
2872
*/
2873
if ((def->nameClass != NULL) || (def->name == NULL))
2874
ret = 0;
2875
else
2876
ret = 1;
2877
return (ret);
2878
case XML_RELAXNG_REF:
2879
case XML_RELAXNG_EXTERNALREF:
2880
case XML_RELAXNG_PARENTREF:
2881
if (def->depth == -20) {
2882
return (1);
2883
} else {
2884
xmlRelaxNGDefinePtr list;
2885
2886
def->depth = -20;
2887
list = def->content;
2888
while (list != NULL) {
2889
ret = xmlRelaxNGIsCompilable(list);
2890
if (ret != 1)
2891
break;
2892
list = list->next;
2893
}
2894
}
2895
break;
2896
case XML_RELAXNG_START:
2897
case XML_RELAXNG_OPTIONAL:
2898
case XML_RELAXNG_ZEROORMORE:
2899
case XML_RELAXNG_ONEORMORE:
2900
case XML_RELAXNG_CHOICE:
2901
case XML_RELAXNG_GROUP:
2902
case XML_RELAXNG_DEF:{
2903
xmlRelaxNGDefinePtr list;
2904
2905
list = def->content;
2906
while (list != NULL) {
2907
ret = xmlRelaxNGIsCompilable(list);
2908
if (ret != 1)
2909
break;
2910
list = list->next;
2911
}
2912
break;
2913
}
2914
case XML_RELAXNG_EXCEPT:
2915
case XML_RELAXNG_ATTRIBUTE:
2916
case XML_RELAXNG_INTERLEAVE:
2917
case XML_RELAXNG_DATATYPE:
2918
case XML_RELAXNG_LIST:
2919
case XML_RELAXNG_PARAM:
2920
case XML_RELAXNG_VALUE:
2921
case XML_RELAXNG_NOT_ALLOWED:
2922
ret = 0;
2923
break;
2924
}
2925
if (ret == 0)
2926
def->dflags |= IS_NOT_COMPILABLE;
2927
if (ret == 1)
2928
def->dflags |= IS_COMPILABLE;
2929
return (ret);
2930
}
2931
2932
/**
2933
* xmlRelaxNGCompile:
2934
* ctxt: the RelaxNG parser context
2935
* @define: the definition tree to compile
2936
*
2937
* Compile the set of definitions, it works recursively, till the
2938
* element boundaries, where it tries to compile the content if possible
2939
*
2940
* Returns 0 if success and -1 in case of error
2941
*/
2942
static int
2943
xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
2944
{
2945
int ret = 0;
2946
xmlRelaxNGDefinePtr list;
2947
2948
if ((ctxt == NULL) || (def == NULL))
2949
return (-1);
2950
2951
switch (def->type) {
2952
case XML_RELAXNG_START:
2953
if ((xmlRelaxNGIsCompilable(def) == 1) && (def->depth != -25)) {
2954
xmlAutomataPtr oldam = ctxt->am;
2955
xmlAutomataStatePtr oldstate = ctxt->state;
2956
2957
def->depth = -25;
2958
2959
list = def->content;
2960
ctxt->am = xmlNewAutomata();
2961
if (ctxt->am == NULL)
2962
return (-1);
2963
2964
/*
2965
* assume identical strings but not same pointer are different
2966
* atoms, needed for non-determinism detection
2967
* That way if 2 elements with the same name are in a choice
2968
* branch the automata is found non-deterministic and
2969
* we fallback to the normal validation which does the right
2970
* thing of exploring both choices.
2971
*/
2972
xmlAutomataSetFlags(ctxt->am, 1);
2973
2974
ctxt->state = xmlAutomataGetInitState(ctxt->am);
2975
while (list != NULL) {
2976
xmlRelaxNGCompile(ctxt, list);
2977
list = list->next;
2978
}
2979
xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2980
if (xmlAutomataIsDeterminist(ctxt->am))
2981
def->contModel = xmlAutomataCompile(ctxt->am);
2982
2983
xmlFreeAutomata(ctxt->am);
2984
ctxt->state = oldstate;
2985
ctxt->am = oldam;
2986
}
2987
break;
2988
case XML_RELAXNG_ELEMENT:
2989
if ((ctxt->am != NULL) && (def->name != NULL)) {
2990
ctxt->state = xmlAutomataNewTransition2(ctxt->am,
2991
ctxt->state, NULL,
2992
def->name, def->ns,
2993
def);
2994
}
2995
if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2996
xmlAutomataPtr oldam = ctxt->am;
2997
xmlAutomataStatePtr oldstate = ctxt->state;
2998
2999
def->depth = -25;
3000
3001
list = def->content;
3002
ctxt->am = xmlNewAutomata();
3003
if (ctxt->am == NULL)
3004
return (-1);
3005
xmlAutomataSetFlags(ctxt->am, 1);
3006
ctxt->state = xmlAutomataGetInitState(ctxt->am);
3007
while (list != NULL) {
3008
xmlRelaxNGCompile(ctxt, list);
3009
list = list->next;
3010
}
3011
xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3012
def->contModel = xmlAutomataCompile(ctxt->am);
3013
if (!xmlRegexpIsDeterminist(def->contModel)) {
3014
/*
3015
* we can only use the automata if it is determinist
3016
*/
3017
xmlRegFreeRegexp(def->contModel);
3018
def->contModel = NULL;
3019
}
3020
xmlFreeAutomata(ctxt->am);
3021
ctxt->state = oldstate;
3022
ctxt->am = oldam;
3023
} else {
3024
xmlAutomataPtr oldam = ctxt->am;
3025
3026
/*
3027
* we can't build the content model for this element content
3028
* but it still might be possible to build it for some of its
3029
* children, recurse.
3030
*/
3031
ret = xmlRelaxNGTryCompile(ctxt, def);
3032
ctxt->am = oldam;
3033
}
3034
break;
3035
case XML_RELAXNG_NOOP:
3036
ret = xmlRelaxNGCompile(ctxt, def->content);
3037
break;
3038
case XML_RELAXNG_OPTIONAL:{
3039
xmlAutomataStatePtr oldstate = ctxt->state;
3040
3041
list = def->content;
3042
while (list != NULL) {
3043
xmlRelaxNGCompile(ctxt, list);
3044
list = list->next;
3045
}
3046
xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3047
break;
3048
}
3049
case XML_RELAXNG_ZEROORMORE:{
3050
xmlAutomataStatePtr oldstate;
3051
3052
ctxt->state =
3053
xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3054
oldstate = ctxt->state;
3055
list = def->content;
3056
while (list != NULL) {
3057
xmlRelaxNGCompile(ctxt, list);
3058
list = list->next;
3059
}
3060
xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3061
ctxt->state =
3062
xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3063
break;
3064
}
3065
case XML_RELAXNG_ONEORMORE:{
3066
xmlAutomataStatePtr oldstate;
3067
3068
list = def->content;
3069
while (list != NULL) {
3070
xmlRelaxNGCompile(ctxt, list);
3071
list = list->next;
3072
}
3073
oldstate = ctxt->state;
3074
list = def->content;
3075
while (list != NULL) {
3076
xmlRelaxNGCompile(ctxt, list);
3077
list = list->next;
3078
}
3079
xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3080
ctxt->state =
3081
xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3082
break;
3083
}
3084
case XML_RELAXNG_CHOICE:{
3085
xmlAutomataStatePtr target = NULL;
3086
xmlAutomataStatePtr oldstate = ctxt->state;
3087
3088
list = def->content;
3089
while (list != NULL) {
3090
ctxt->state = oldstate;
3091
ret = xmlRelaxNGCompile(ctxt, list);
3092
if (ret != 0)
3093
break;
3094
if (target == NULL)
3095
target = ctxt->state;
3096
else {
3097
xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3098
target);
3099
}
3100
list = list->next;
3101
}
3102
ctxt->state = target;
3103
3104
break;
3105
}
3106
case XML_RELAXNG_REF:
3107
case XML_RELAXNG_EXTERNALREF:
3108
case XML_RELAXNG_PARENTREF:
3109
case XML_RELAXNG_GROUP:
3110
case XML_RELAXNG_DEF:
3111
list = def->content;
3112
while (list != NULL) {
3113
ret = xmlRelaxNGCompile(ctxt, list);
3114
if (ret != 0)
3115
break;
3116
list = list->next;
3117
}
3118
break;
3119
case XML_RELAXNG_TEXT:{
3120
xmlAutomataStatePtr oldstate;
3121
3122
ctxt->state =
3123
xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3124
oldstate = ctxt->state;
3125
xmlRelaxNGCompile(ctxt, def->content);
3126
xmlAutomataNewTransition(ctxt->am, ctxt->state,
3127
ctxt->state, BAD_CAST "#text",
3128
NULL);
3129
ctxt->state =
3130
xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3131
break;
3132
}
3133
case XML_RELAXNG_EMPTY:
3134
ctxt->state =
3135
xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3136
break;
3137
case XML_RELAXNG_EXCEPT:
3138
case XML_RELAXNG_ATTRIBUTE:
3139
case XML_RELAXNG_INTERLEAVE:
3140
case XML_RELAXNG_NOT_ALLOWED:
3141
case XML_RELAXNG_DATATYPE:
3142
case XML_RELAXNG_LIST:
3143
case XML_RELAXNG_PARAM:
3144
case XML_RELAXNG_VALUE:
3145
/* This should not happen and generate an internal error */
3146
fprintf(stderr, "RNG internal error trying to compile %s\n",
3147
xmlRelaxNGDefName(def));
3148
break;
3149
}
3150
return (ret);
3151
}
3152
3153
/**
3154
* xmlRelaxNGTryCompile:
3155
* ctxt: the RelaxNG parser context
3156
* @define: the definition tree to compile
3157
*
3158
* Try to compile the set of definitions, it works recursively,
3159
* possibly ignoring parts which cannot be compiled.
3160
*
3161
* Returns 0 if success and -1 in case of error
3162
*/
3163
static int
3164
xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3165
{
3166
int ret = 0;
3167
xmlRelaxNGDefinePtr list;
3168
3169
if ((ctxt == NULL) || (def == NULL))
3170
return (-1);
3171
3172
if ((def->type == XML_RELAXNG_START) ||
3173
(def->type == XML_RELAXNG_ELEMENT)) {
3174
ret = xmlRelaxNGIsCompilable(def);
3175
if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3176
ctxt->am = NULL;
3177
ret = xmlRelaxNGCompile(ctxt, def);
3178
return (ret);
3179
}
3180
}
3181
switch (def->type) {
3182
case XML_RELAXNG_NOOP:
3183
ret = xmlRelaxNGTryCompile(ctxt, def->content);
3184
break;
3185
case XML_RELAXNG_TEXT:
3186
case XML_RELAXNG_DATATYPE:
3187
case XML_RELAXNG_LIST:
3188
case XML_RELAXNG_PARAM:
3189
case XML_RELAXNG_VALUE:
3190
case XML_RELAXNG_EMPTY:
3191
case XML_RELAXNG_ELEMENT:
3192
ret = 0;
3193
break;
3194
case XML_RELAXNG_OPTIONAL:
3195
case XML_RELAXNG_ZEROORMORE:
3196
case XML_RELAXNG_ONEORMORE:
3197
case XML_RELAXNG_CHOICE:
3198
case XML_RELAXNG_GROUP:
3199
case XML_RELAXNG_DEF:
3200
case XML_RELAXNG_START:
3201
case XML_RELAXNG_REF:
3202
case XML_RELAXNG_EXTERNALREF:
3203
case XML_RELAXNG_PARENTREF:
3204
list = def->content;
3205
while (list != NULL) {
3206
ret = xmlRelaxNGTryCompile(ctxt, list);
3207
if (ret != 0)
3208
break;
3209
list = list->next;
3210
}
3211
break;
3212
case XML_RELAXNG_EXCEPT:
3213
case XML_RELAXNG_ATTRIBUTE:
3214
case XML_RELAXNG_INTERLEAVE:
3215
case XML_RELAXNG_NOT_ALLOWED:
3216
ret = 0;
3217
break;
3218
}
3219
return (ret);
3220
}
3221
3222
/************************************************************************
3223
* *
3224
* Parsing functions *
3225
* *
3226
************************************************************************/
3227
3228
static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3229
ctxt, xmlNodePtr node);
3230
static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3231
ctxt, xmlNodePtr node);
3232
static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3233
ctxt, xmlNodePtr nodes,
3234
int group);
3235
static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3236
ctxt, xmlNodePtr node);
3237
static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3238
xmlNodePtr node);
3239
static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3240
xmlNodePtr nodes);
3241
static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3242
ctxt, xmlNodePtr node,
3243
xmlRelaxNGDefinePtr
3244
def);
3245
static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3246
ctxt, xmlNodePtr nodes);
3247
static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3248
xmlRelaxNGDefinePtr define,
3249
xmlNodePtr elem);
3250
3251
3252
#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3253
3254
/**
3255
* xmlRelaxNGIsNullable:
3256
* @define: the definition to verify
3257
*
3258
* Check if a definition is nullable.
3259
*
3260
* Returns 1 if yes, 0 if no and -1 in case of error
3261
*/
3262
static int
3263
xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3264
{
3265
int ret;
3266
3267
if (define == NULL)
3268
return (-1);
3269
3270
if (define->dflags & IS_NULLABLE)
3271
return (1);
3272
if (define->dflags & IS_NOT_NULLABLE)
3273
return (0);
3274
switch (define->type) {
3275
case XML_RELAXNG_EMPTY:
3276
case XML_RELAXNG_TEXT:
3277
ret = 1;
3278
break;
3279
case XML_RELAXNG_NOOP:
3280
case XML_RELAXNG_DEF:
3281
case XML_RELAXNG_REF:
3282
case XML_RELAXNG_EXTERNALREF:
3283
case XML_RELAXNG_PARENTREF:
3284
case XML_RELAXNG_ONEORMORE:
3285
ret = xmlRelaxNGIsNullable(define->content);
3286
break;
3287
case XML_RELAXNG_EXCEPT:
3288
case XML_RELAXNG_NOT_ALLOWED:
3289
case XML_RELAXNG_ELEMENT:
3290
case XML_RELAXNG_DATATYPE:
3291
case XML_RELAXNG_PARAM:
3292
case XML_RELAXNG_VALUE:
3293
case XML_RELAXNG_LIST:
3294
case XML_RELAXNG_ATTRIBUTE:
3295
ret = 0;
3296
break;
3297
case XML_RELAXNG_CHOICE:{
3298
xmlRelaxNGDefinePtr list = define->content;
3299
3300
while (list != NULL) {
3301
ret = xmlRelaxNGIsNullable(list);
3302
if (ret != 0)
3303
goto done;
3304
list = list->next;
3305
}
3306
ret = 0;
3307
break;
3308
}
3309
case XML_RELAXNG_START:
3310
case XML_RELAXNG_INTERLEAVE:
3311
case XML_RELAXNG_GROUP:{
3312
xmlRelaxNGDefinePtr list = define->content;
3313
3314
while (list != NULL) {
3315
ret = xmlRelaxNGIsNullable(list);
3316
if (ret != 1)
3317
goto done;
3318
list = list->next;
3319
}
3320
return (1);
3321
}
3322
default:
3323
return (-1);
3324
}
3325
done:
3326
if (ret == 0)
3327
define->dflags |= IS_NOT_NULLABLE;
3328
if (ret == 1)
3329
define->dflags |= IS_NULLABLE;
3330
return (ret);
3331
}
3332
3333
/**
3334
* xmlRelaxNGIsBlank:
3335
* @str: a string
3336
*
3337
* Check if a string is ignorable c.f. 4.2. Whitespace
3338
*
3339
* Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3340
*/
3341
static int
3342
xmlRelaxNGIsBlank(xmlChar * str)
3343
{
3344
if (str == NULL)
3345
return (1);
3346
while (*str != 0) {
3347
if (!(IS_BLANK_CH(*str)))
3348
return (0);
3349
str++;
3350
}
3351
return (1);
3352
}
3353
3354
/**
3355
* xmlRelaxNGGetDataTypeLibrary:
3356
* @ctxt: a Relax-NG parser context
3357
* @node: the current data or value element
3358
*
3359
* Applies algorithm from 4.3. datatypeLibrary attribute
3360
*
3361
* Returns the datatypeLibrary value or NULL if not found
3362
*/
3363
static xmlChar *
3364
xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3365
xmlNodePtr node)
3366
{
3367
xmlChar *ret, *escape;
3368
3369
if (node == NULL)
3370
return(NULL);
3371
3372
if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3373
ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3374
if (ret != NULL) {
3375
if (ret[0] == 0) {
3376
xmlFree(ret);
3377
return (NULL);
3378
}
3379
escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3380
if (escape == NULL) {
3381
return (ret);
3382
}
3383
xmlFree(ret);
3384
return (escape);
3385
}
3386
}
3387
node = node->parent;
3388
while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
3389
ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3390
if (ret != NULL) {
3391
if (ret[0] == 0) {
3392
xmlFree(ret);
3393
return (NULL);
3394
}
3395
escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3396
if (escape == NULL) {
3397
return (ret);
3398
}
3399
xmlFree(ret);
3400
return (escape);
3401
}
3402
node = node->parent;
3403
}
3404
return (NULL);
3405
}
3406
3407
/**
3408
* xmlRelaxNGParseValue:
3409
* @ctxt: a Relax-NG parser context
3410
* @node: the data node.
3411
*
3412
* parse the content of a RelaxNG value node.
3413
*
3414
* Returns the definition pointer or NULL in case of error
3415
*/
3416
static xmlRelaxNGDefinePtr
3417
xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3418
{
3419
xmlRelaxNGDefinePtr def = NULL;
3420
xmlRelaxNGTypeLibraryPtr lib = NULL;
3421
xmlChar *type;
3422
xmlChar *library;
3423
int success = 0;
3424
3425
def = xmlRelaxNGNewDefine(ctxt, node);
3426
if (def == NULL)
3427
return (NULL);
3428
def->type = XML_RELAXNG_VALUE;
3429
3430
type = xmlGetProp(node, BAD_CAST "type");
3431
if (type != NULL) {
3432
xmlRelaxNGNormExtSpace(type);
3433
if (xmlValidateNCName(type, 0)) {
3434
xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3435
"value type '%s' is not an NCName\n", type, NULL);
3436
}
3437
library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3438
if (library == NULL)
3439
library =
3440
xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3441
3442
def->name = type;
3443
def->ns = library;
3444
3445
lib = (xmlRelaxNGTypeLibraryPtr)
3446
xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3447
if (lib == NULL) {
3448
xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3449
"Use of unregistered type library '%s'\n", library,
3450
NULL);
3451
def->data = NULL;
3452
} else {
3453
def->data = lib;
3454
if (lib->have == NULL) {
3455
xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3456
"Internal error with type library '%s': no 'have'\n",
3457
library, NULL);
3458
} else {
3459
success = lib->have(lib->data, def->name);
3460
if (success != 1) {
3461
xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3462
"Error type '%s' is not exported by type library '%s'\n",
3463
def->name, library);
3464
}
3465
}
3466
}
3467
}
3468
if (node->children == NULL) {
3469
def->value = xmlStrdup(BAD_CAST "");
3470
} else if (((node->children->type != XML_TEXT_NODE) &&
3471
(node->children->type != XML_CDATA_SECTION_NODE)) ||
3472
(node->children->next != NULL)) {
3473
xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3474
"Expecting a single text value for <value>content\n",
3475
NULL, NULL);
3476
} else if (def != NULL) {
3477
def->value = xmlNodeGetContent(node);
3478
if (def->value == NULL) {
3479
xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3480
"Element <value> has no content\n", NULL, NULL);
3481
} else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3482
void *val = NULL;
3483
3484
success =
3485
lib->check(lib->data, def->name, def->value, &val, node);
3486
if (success != 1) {
3487
xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3488
"Value '%s' is not acceptable for type '%s'\n",
3489
def->value, def->name);
3490
} else {
3491
if (val != NULL)
3492
def->attrs = val;
3493
}
3494
}
3495
}
3496
return (def);
3497
}
3498
3499
/**
3500
* xmlRelaxNGParseData:
3501
* @ctxt: a Relax-NG parser context
3502
* @node: the data node.
3503
*
3504
* parse the content of a RelaxNG data node.
3505
*
3506
* Returns the definition pointer or NULL in case of error
3507
*/
3508
static xmlRelaxNGDefinePtr
3509
xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3510
{
3511
xmlRelaxNGDefinePtr def = NULL, except;
3512
xmlRelaxNGDefinePtr param, lastparam = NULL;
3513
xmlRelaxNGTypeLibraryPtr lib;
3514
xmlChar *type;
3515
xmlChar *library;
3516
xmlNodePtr content;
3517
int tmp;
3518
3519
type = xmlGetProp(node, BAD_CAST "type");
3520
if (type == NULL) {
3521
xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3522
NULL);
3523
return (NULL);
3524
}
3525
xmlRelaxNGNormExtSpace(type);
3526
if (xmlValidateNCName(type, 0)) {
3527
xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3528
"data type '%s' is not an NCName\n", type, NULL);
3529
}
3530
library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3531
if (library == NULL)
3532
library =
3533
xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3534
3535
def = xmlRelaxNGNewDefine(ctxt, node);
3536
if (def == NULL) {
3537
xmlFree(library);
3538
xmlFree(type);
3539
return (NULL);
3540
}
3541
def->type = XML_RELAXNG_DATATYPE;
3542
def->name = type;
3543
def->ns = library;
3544
3545
lib = (xmlRelaxNGTypeLibraryPtr)
3546
xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3547
if (lib == NULL) {
3548
xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3549
"Use of unregistered type library '%s'\n", library,
3550
NULL);
3551
def->data = NULL;
3552
} else {
3553
def->data = lib;
3554
if (lib->have == NULL) {
3555
xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3556
"Internal error with type library '%s': no 'have'\n",
3557
library, NULL);
3558
} else {
3559
tmp = lib->have(lib->data, def->name);
3560
if (tmp != 1) {
3561
xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3562
"Error type '%s' is not exported by type library '%s'\n",
3563
def->name, library);
3564
} else
3565
if ((xmlStrEqual
3566
(library,
3567
BAD_CAST
3568
"http://www.w3.org/2001/XMLSchema-datatypes"))
3569
&& ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3570
|| (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3571
ctxt->idref = 1;
3572
}
3573
}
3574
}
3575
content = node->children;
3576
3577
/*
3578
* Handle optional params
3579
*/
3580
while (content != NULL) {
3581
if (!xmlStrEqual(content->name, BAD_CAST "param"))
3582
break;
3583
if (xmlStrEqual(library,
3584
BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3585
xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3586
"Type library '%s' does not allow type parameters\n",
3587
library, NULL);
3588
content = content->next;
3589
while ((content != NULL) &&
3590
(xmlStrEqual(content->name, BAD_CAST "param")))
3591
content = content->next;
3592
} else {
3593
param = xmlRelaxNGNewDefine(ctxt, node);
3594
if (param != NULL) {
3595
param->type = XML_RELAXNG_PARAM;
3596
param->name = xmlGetProp(content, BAD_CAST "name");
3597
if (param->name == NULL) {
3598
xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3599
"param has no name\n", NULL, NULL);
3600
}
3601
param->value = xmlNodeGetContent(content);
3602
if (lastparam == NULL) {
3603
def->attrs = lastparam = param;
3604
} else {
3605
lastparam->next = param;
3606
lastparam = param;
3607
}
3608
if (lib != NULL) {
3609
}
3610
}
3611
content = content->next;
3612
}
3613
}
3614
/*
3615
* Handle optional except
3616
*/
3617
if ((content != NULL)
3618
&& (xmlStrEqual(content->name, BAD_CAST "except"))) {
3619
xmlNodePtr child;
3620
xmlRelaxNGDefinePtr tmp2, last = NULL;
3621
3622
except = xmlRelaxNGNewDefine(ctxt, node);
3623
if (except == NULL) {
3624
return (def);
3625
}
3626
except->type = XML_RELAXNG_EXCEPT;
3627
child = content->children;
3628
def->content = except;
3629
if (child == NULL) {
3630
xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3631
"except has no content\n", NULL, NULL);
3632
}
3633
while (child != NULL) {
3634
tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3635
if (tmp2 != NULL) {
3636
if (last == NULL) {
3637
except->content = last = tmp2;
3638
} else {
3639
last->next = tmp2;
3640
last = tmp2;
3641
}
3642
}
3643
child = child->next;
3644
}
3645
content = content->next;
3646
}
3647
/*
3648
* Check there is no unhandled data
3649
*/
3650
if (content != NULL) {
3651
xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3652
"Element data has unexpected content %s\n",
3653
content->name, NULL);
3654
}
3655
3656
return (def);
3657
}
3658
3659
static const xmlChar *invalidName = BAD_CAST "\1";
3660
3661
/**
3662
* xmlRelaxNGCompareNameClasses:
3663
* @defs1: the first element/attribute defs
3664
* @defs2: the second element/attribute defs
3665
* @name: the restriction on the name
3666
* @ns: the restriction on the namespace
3667
*
3668
* Compare the 2 lists of element definitions. The comparison is
3669
* that if both lists do not accept the same QNames, it returns 1
3670
* If the 2 lists can accept the same QName the comparison returns 0
3671
*
3672
* Returns 1 distinct, 0 if equal
3673
*/
3674
static int
3675
xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3676
xmlRelaxNGDefinePtr def2)
3677
{
3678
int ret = 1;
3679
xmlNode node;
3680
xmlNs ns;
3681
xmlRelaxNGValidCtxt ctxt;
3682
3683
memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3684
3685
ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3686
3687
if ((def1->type == XML_RELAXNG_ELEMENT) ||
3688
(def1->type == XML_RELAXNG_ATTRIBUTE)) {
3689
if (def2->type == XML_RELAXNG_TEXT)
3690
return (1);
3691
if (def1->name != NULL) {
3692
node.name = def1->name;
3693
} else {
3694
node.name = invalidName;
3695
}
3696
if (def1->ns != NULL) {
3697
if (def1->ns[0] == 0) {
3698
node.ns = NULL;
3699
} else {
3700
node.ns = &ns;
3701
ns.href = def1->ns;
3702
}
3703
} else {
3704
node.ns = NULL;
3705
}
3706
if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
3707
if (def1->nameClass != NULL) {
3708
ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3709
} else {
3710
ret = 0;
3711
}
3712
} else {
3713
ret = 1;
3714
}
3715
} else if (def1->type == XML_RELAXNG_TEXT) {
3716
if (def2->type == XML_RELAXNG_TEXT)
3717
return (0);
3718
return (1);
3719
} else if (def1->type == XML_RELAXNG_EXCEPT) {
3720
ret = xmlRelaxNGCompareNameClasses(def1->content, def2);
3721
if (ret == 0)
3722
ret = 1;
3723
else if (ret == 1)
3724
ret = 0;
3725
} else {
3726
TODO ret = 0;
3727
}
3728
if (ret == 0)
3729
return (ret);
3730
if ((def2->type == XML_RELAXNG_ELEMENT) ||
3731
(def2->type == XML_RELAXNG_ATTRIBUTE)) {
3732
if (def2->name != NULL) {
3733
node.name = def2->name;
3734
} else {
3735
node.name = invalidName;
3736
}
3737
node.ns = &ns;
3738
if (def2->ns != NULL) {
3739
if (def2->ns[0] == 0) {
3740
node.ns = NULL;
3741
} else {
3742
ns.href = def2->ns;
3743
}
3744
} else {
3745
ns.href = invalidName;
3746
}
3747
if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
3748
if (def2->nameClass != NULL) {
3749
ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3750
} else {
3751
ret = 0;
3752
}
3753
} else {
3754
ret = 1;
3755
}
3756
} else {
3757
TODO ret = 0;
3758
}
3759
3760
return (ret);
3761
}
3762
3763
/**
3764
* xmlRelaxNGCompareElemDefLists:
3765
* @ctxt: a Relax-NG parser context
3766
* @defs1: the first list of element/attribute defs
3767
* @defs2: the second list of element/attribute defs
3768
*
3769
* Compare the 2 lists of element or attribute definitions. The comparison
3770
* is that if both lists do not accept the same QNames, it returns 1
3771
* If the 2 lists can accept the same QName the comparison returns 0
3772
*
3773
* Returns 1 distinct, 0 if equal
3774
*/
3775
static int
3776
xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3777
ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3778
xmlRelaxNGDefinePtr * def2)
3779
{
3780
xmlRelaxNGDefinePtr *basedef2 = def2;
3781
3782
if ((def1 == NULL) || (def2 == NULL))
3783
return (1);
3784
if ((*def1 == NULL) || (*def2 == NULL))
3785
return (1);
3786
while (*def1 != NULL) {
3787
while ((*def2) != NULL) {
3788
if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3789
return (0);
3790
def2++;
3791
}
3792
def2 = basedef2;
3793
def1++;
3794
}
3795
return (1);
3796
}
3797
3798
/**
3799
* xmlRelaxNGGenerateAttributes:
3800
* @ctxt: a Relax-NG parser context
3801
* @def: the definition definition
3802
*
3803
* Check if the definition can only generate attributes
3804
*
3805
* Returns 1 if yes, 0 if no and -1 in case of error.
3806
*/
3807
static int
3808
xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3809
xmlRelaxNGDefinePtr def)
3810
{
3811
xmlRelaxNGDefinePtr parent, cur, tmp;
3812
3813
/*
3814
* Don't run that check in case of error. Infinite recursion
3815
* becomes possible.
3816
*/
3817
if (ctxt->nbErrors != 0)
3818
return (-1);
3819
3820
parent = NULL;
3821
cur = def;
3822
while (cur != NULL) {
3823
if ((cur->type == XML_RELAXNG_ELEMENT) ||
3824
(cur->type == XML_RELAXNG_TEXT) ||
3825
(cur->type == XML_RELAXNG_DATATYPE) ||
3826
(cur->type == XML_RELAXNG_PARAM) ||
3827
(cur->type == XML_RELAXNG_LIST) ||
3828
(cur->type == XML_RELAXNG_VALUE) ||
3829
(cur->type == XML_RELAXNG_EMPTY))
3830
return (0);
3831
if ((cur->type == XML_RELAXNG_CHOICE) ||
3832
(cur->type == XML_RELAXNG_INTERLEAVE) ||
3833
(cur->type == XML_RELAXNG_GROUP) ||
3834
(cur->type == XML_RELAXNG_ONEORMORE) ||
3835
(cur->type == XML_RELAXNG_ZEROORMORE) ||
3836
(cur->type == XML_RELAXNG_OPTIONAL) ||
3837
(cur->type == XML_RELAXNG_PARENTREF) ||
3838
(cur->type == XML_RELAXNG_EXTERNALREF) ||
3839
(cur->type == XML_RELAXNG_REF) ||
3840
(cur->type == XML_RELAXNG_DEF)) {
3841
if (cur->content != NULL) {
3842
parent = cur;
3843
cur = cur->content;
3844
tmp = cur;
3845
while (tmp != NULL) {
3846
tmp->parent = parent;
3847
tmp = tmp->next;
3848
}
3849
continue;
3850
}
3851
}
3852
if (cur == def)
3853
break;
3854
if (cur->next != NULL) {
3855
cur = cur->next;
3856
continue;
3857
}
3858
do {
3859
cur = cur->parent;
3860
if (cur == NULL)
3861
break;
3862
if (cur == def)
3863
return (1);
3864
if (cur->next != NULL) {
3865
cur = cur->next;
3866
break;
3867
}
3868
} while (cur != NULL);
3869
}
3870
return (1);
3871
}
3872
3873
/**
3874
* xmlRelaxNGGetElements:
3875
* @ctxt: a Relax-NG parser context
3876
* @def: the definition definition
3877
* @eora: gather elements (0), attributes (1) or elements and text (2)
3878
*
3879
* Compute the list of top elements a definition can generate
3880
*
3881
* Returns a list of elements or NULL if none was found.
3882
*/
3883
static xmlRelaxNGDefinePtr *
3884
xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
3885
xmlRelaxNGDefinePtr def, int eora)
3886
{
3887
xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
3888
int len = 0;
3889
int max = 0;
3890
3891
/*
3892
* Don't run that check in case of error. Infinite recursion
3893
* becomes possible.
3894
*/
3895
if (ctxt->nbErrors != 0)
3896
return (NULL);
3897
3898
parent = NULL;
3899
cur = def;
3900
while (cur != NULL) {
3901
if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3902
(cur->type == XML_RELAXNG_TEXT))) ||
3903
((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE)) ||
3904
((eora == 2) && ((cur->type == XML_RELAXNG_DATATYPE) ||
3905
(cur->type == XML_RELAXNG_ELEMENT) ||
3906
(cur->type == XML_RELAXNG_LIST) ||
3907
(cur->type == XML_RELAXNG_TEXT) ||
3908
(cur->type == XML_RELAXNG_VALUE)))) {
3909
if (ret == NULL) {
3910
max = 10;
3911
ret = (xmlRelaxNGDefinePtr *)
3912
xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3913
if (ret == NULL) {
3914
xmlRngPErrMemory(ctxt, "getting element list\n");
3915
return (NULL);
3916
}
3917
} else if (max <= len) {
3918
xmlRelaxNGDefinePtr *temp;
3919
3920
max *= 2;
3921
temp = xmlRealloc(ret,
3922
(max + 1) * sizeof(xmlRelaxNGDefinePtr));
3923
if (temp == NULL) {
3924
xmlRngPErrMemory(ctxt, "getting element list\n");
3925
xmlFree(ret);
3926
return (NULL);
3927
}
3928
ret = temp;
3929
}
3930
ret[len++] = cur;
3931
ret[len] = NULL;
3932
} else if ((cur->type == XML_RELAXNG_CHOICE) ||
3933
(cur->type == XML_RELAXNG_INTERLEAVE) ||
3934
(cur->type == XML_RELAXNG_GROUP) ||
3935
(cur->type == XML_RELAXNG_ONEORMORE) ||
3936
(cur->type == XML_RELAXNG_ZEROORMORE) ||
3937
(cur->type == XML_RELAXNG_OPTIONAL) ||
3938
(cur->type == XML_RELAXNG_PARENTREF) ||
3939
(cur->type == XML_RELAXNG_REF) ||
3940
(cur->type == XML_RELAXNG_DEF) ||
3941
(cur->type == XML_RELAXNG_EXTERNALREF)) {
3942
/*
3943
* Don't go within elements or attributes or string values.
3944
* Just gather the element top list
3945
*/
3946
if (cur->content != NULL) {
3947
parent = cur;
3948
cur = cur->content;
3949
tmp = cur;
3950
while (tmp != NULL) {
3951
tmp->parent = parent;
3952
tmp = tmp->next;
3953
}
3954
continue;
3955
}
3956
}
3957
if (cur == def)
3958
break;
3959
if (cur->next != NULL) {
3960
cur = cur->next;
3961
continue;
3962
}
3963
do {
3964
cur = cur->parent;
3965
if (cur == NULL)
3966
break;
3967
if (cur == def)
3968
return (ret);
3969
if (cur->next != NULL) {
3970
cur = cur->next;
3971
break;
3972
}
3973
} while (cur != NULL);
3974
}
3975
return (ret);
3976
}
3977
3978
/**
3979
* xmlRelaxNGCheckChoiceDeterminism:
3980
* @ctxt: a Relax-NG parser context
3981
* @def: the choice definition
3982
*
3983
* Also used to find indeterministic pattern in choice
3984
*/
3985
static void
3986
xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3987
xmlRelaxNGDefinePtr def)
3988
{
3989
xmlRelaxNGDefinePtr **list;
3990
xmlRelaxNGDefinePtr cur;
3991
int nbchild = 0, i, j, ret;
3992
int is_nullable = 0;
3993
int is_indeterminist = 0;
3994
xmlHashTablePtr triage = NULL;
3995
int is_triable = 1;
3996
3997
if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
3998
return;
3999
4000
if (def->dflags & IS_PROCESSED)
4001
return;
4002
4003
/*
4004
* Don't run that check in case of error. Infinite recursion
4005
* becomes possible.
4006
*/
4007
if (ctxt->nbErrors != 0)
4008
return;
4009
4010
is_nullable = xmlRelaxNGIsNullable(def);
4011
4012
cur = def->content;
4013
while (cur != NULL) {
4014
nbchild++;
4015
cur = cur->next;
4016
}
4017
4018
list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4019
sizeof(xmlRelaxNGDefinePtr
4020
*));
4021
if (list == NULL) {
4022
xmlRngPErrMemory(ctxt, "building choice\n");
4023
return;
4024
}
4025
i = 0;
4026
/*
4027
* a bit strong but safe
4028
*/
4029
if (is_nullable == 0) {
4030
triage = xmlHashCreate(10);
4031
} else {
4032
is_triable = 0;
4033
}
4034
cur = def->content;
4035
while (cur != NULL) {
4036
list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4037
if ((list[i] == NULL) || (list[i][0] == NULL)) {
4038
is_triable = 0;
4039
} else if (is_triable == 1) {
4040
xmlRelaxNGDefinePtr *tmp;
4041
int res;
4042
4043
tmp = list[i];
4044
while ((*tmp != NULL) && (is_triable == 1)) {
4045
if ((*tmp)->type == XML_RELAXNG_TEXT) {
4046
res = xmlHashAddEntry2(triage,
4047
BAD_CAST "#text", NULL,
4048
(void *) cur);
4049
if (res != 0)
4050
is_triable = -1;
4051
} else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4052
((*tmp)->name != NULL)) {
4053
if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4054
res = xmlHashAddEntry2(triage,
4055
(*tmp)->name, NULL,
4056
(void *) cur);
4057
else
4058
res = xmlHashAddEntry2(triage,
4059
(*tmp)->name, (*tmp)->ns,
4060
(void *) cur);
4061
if (res != 0)
4062
is_triable = -1;
4063
} else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4064
if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4065
res = xmlHashAddEntry2(triage,
4066
BAD_CAST "#any", NULL,
4067
(void *) cur);
4068
else
4069
res = xmlHashAddEntry2(triage,
4070
BAD_CAST "#any", (*tmp)->ns,
4071
(void *) cur);
4072
if (res != 0)
4073
is_triable = -1;
4074
} else {
4075
is_triable = -1;
4076
}
4077
tmp++;
4078
}
4079
}
4080
i++;
4081
cur = cur->next;
4082
}
4083
4084
for (i = 0; i < nbchild; i++) {
4085
if (list[i] == NULL)
4086
continue;
4087
for (j = 0; j < i; j++) {
4088
if (list[j] == NULL)
4089
continue;
4090
ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4091
if (ret == 0) {
4092
is_indeterminist = 1;
4093
}
4094
}
4095
}
4096
for (i = 0; i < nbchild; i++) {
4097
if (list[i] != NULL)
4098
xmlFree(list[i]);
4099
}
4100
4101
xmlFree(list);
4102
if (is_indeterminist) {
4103
def->dflags |= IS_INDETERMINIST;
4104
}
4105
if (is_triable == 1) {
4106
def->dflags |= IS_TRIABLE;
4107
def->data = triage;
4108
} else if (triage != NULL) {
4109
xmlHashFree(triage, NULL);
4110
}
4111
def->dflags |= IS_PROCESSED;
4112
}
4113
4114
/**
4115
* xmlRelaxNGCheckGroupAttrs:
4116
* @ctxt: a Relax-NG parser context
4117
* @def: the group definition
4118
*
4119
* Detects violations of rule 7.3
4120
*/
4121
static void
4122
xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
4123
xmlRelaxNGDefinePtr def)
4124
{
4125
xmlRelaxNGDefinePtr **list;
4126
xmlRelaxNGDefinePtr cur;
4127
int nbchild = 0, i, j, ret;
4128
4129
if ((def == NULL) ||
4130
((def->type != XML_RELAXNG_GROUP) &&
4131
(def->type != XML_RELAXNG_ELEMENT)))
4132
return;
4133
4134
if (def->dflags & IS_PROCESSED)
4135
return;
4136
4137
/*
4138
* Don't run that check in case of error. Infinite recursion
4139
* becomes possible.
4140
*/
4141
if (ctxt->nbErrors != 0)
4142
return;
4143
4144
cur = def->attrs;
4145
while (cur != NULL) {
4146
nbchild++;
4147
cur = cur->next;
4148
}
4149
cur = def->content;
4150
while (cur != NULL) {
4151
nbchild++;
4152
cur = cur->next;
4153
}
4154
4155
list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4156
sizeof(xmlRelaxNGDefinePtr
4157
*));
4158
if (list == NULL) {
4159
xmlRngPErrMemory(ctxt, "building group\n");
4160
return;
4161
}
4162
i = 0;
4163
cur = def->attrs;
4164
while (cur != NULL) {
4165
list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4166
i++;
4167
cur = cur->next;
4168
}
4169
cur = def->content;
4170
while (cur != NULL) {
4171
list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4172
i++;
4173
cur = cur->next;
4174
}
4175
4176
for (i = 0; i < nbchild; i++) {
4177
if (list[i] == NULL)
4178
continue;
4179
for (j = 0; j < i; j++) {
4180
if (list[j] == NULL)
4181
continue;
4182
ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4183
if (ret == 0) {
4184
xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4185
"Attributes conflicts in group\n", NULL, NULL);
4186
}
4187
}
4188
}
4189
for (i = 0; i < nbchild; i++) {
4190
if (list[i] != NULL)
4191
xmlFree(list[i]);
4192
}
4193
4194
xmlFree(list);
4195
def->dflags |= IS_PROCESSED;
4196
}
4197
4198
/**
4199
* xmlRelaxNGComputeInterleaves:
4200
* @def: the interleave definition
4201
* @ctxt: a Relax-NG parser context
4202
* @name: the definition name
4203
*
4204
* A lot of work for preprocessing interleave definitions
4205
* is potentially needed to get a decent execution speed at runtime
4206
* - trying to get a total order on the element nodes generated
4207
* by the interleaves, order the list of interleave definitions
4208
* following that order.
4209
* - if <text/> is used to handle mixed content, it is better to
4210
* flag this in the define and simplify the runtime checking
4211
* algorithm
4212
*/
4213
static void
4214
xmlRelaxNGComputeInterleaves(void *payload, void *data,
4215
const xmlChar * name ATTRIBUTE_UNUSED)
4216
{
4217
xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4218
xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4219
xmlRelaxNGDefinePtr cur, *tmp;
4220
4221
xmlRelaxNGPartitionPtr partitions = NULL;
4222
xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4223
xmlRelaxNGInterleaveGroupPtr group;
4224
int i, j, ret, res;
4225
int nbgroups = 0;
4226
int nbchild = 0;
4227
int is_mixed = 0;
4228
int is_determinist = 1;
4229
4230
/*
4231
* Don't run that check in case of error. Infinite recursion
4232
* becomes possible.
4233
*/
4234
if (ctxt->nbErrors != 0)
4235
return;
4236
4237
cur = def->content;
4238
while (cur != NULL) {
4239
nbchild++;
4240
cur = cur->next;
4241
}
4242
4243
groups = (xmlRelaxNGInterleaveGroupPtr *)
4244
xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4245
if (groups == NULL)
4246
goto error;
4247
cur = def->content;
4248
while (cur != NULL) {
4249
groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4250
xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4251
if (groups[nbgroups] == NULL)
4252
goto error;
4253
if (cur->type == XML_RELAXNG_TEXT)
4254
is_mixed++;
4255
groups[nbgroups]->rule = cur;
4256
groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 2);
4257
groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4258
nbgroups++;
4259
cur = cur->next;
4260
}
4261
4262
/*
4263
* Let's check that all rules makes a partitions according to 7.4
4264
*/
4265
partitions = (xmlRelaxNGPartitionPtr)
4266
xmlMalloc(sizeof(xmlRelaxNGPartition));
4267
if (partitions == NULL)
4268
goto error;
4269
memset(partitions, 0, sizeof(xmlRelaxNGPartition));
4270
partitions->nbgroups = nbgroups;
4271
partitions->triage = xmlHashCreate(nbgroups);
4272
for (i = 0; i < nbgroups; i++) {
4273
group = groups[i];
4274
for (j = i + 1; j < nbgroups; j++) {
4275
if (groups[j] == NULL)
4276
continue;
4277
4278
ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4279
groups[j]->defs);
4280
if (ret == 0) {
4281
xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4282
"Element or text conflicts in interleave\n",
4283
NULL, NULL);
4284
}
4285
ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4286
groups[j]->attrs);
4287
if (ret == 0) {
4288
xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4289
"Attributes conflicts in interleave\n", NULL,
4290
NULL);
4291
}
4292
}
4293
tmp = group->defs;
4294
if ((tmp != NULL) && (*tmp != NULL)) {
4295
while (*tmp != NULL) {
4296
if ((*tmp)->type == XML_RELAXNG_TEXT) {
4297
res = xmlHashAddEntry2(partitions->triage,
4298
BAD_CAST "#text", NULL,
4299
(void *) (ptrdiff_t) (i + 1));
4300
if (res != 0)
4301
is_determinist = -1;
4302
} else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4303
((*tmp)->name != NULL)) {
4304
if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4305
res = xmlHashAddEntry2(partitions->triage,
4306
(*tmp)->name, NULL,
4307
(void *) (ptrdiff_t) (i + 1));
4308
else
4309
res = xmlHashAddEntry2(partitions->triage,
4310
(*tmp)->name, (*tmp)->ns,
4311
(void *) (ptrdiff_t) (i + 1));
4312
if (res != 0)
4313
is_determinist = -1;
4314
} else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4315
if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4316
res = xmlHashAddEntry2(partitions->triage,
4317
BAD_CAST "#any", NULL,
4318
(void *) (ptrdiff_t) (i + 1));
4319
else
4320
res = xmlHashAddEntry2(partitions->triage,
4321
BAD_CAST "#any", (*tmp)->ns,
4322
(void *) (ptrdiff_t) (i + 1));
4323
if ((*tmp)->nameClass != NULL)
4324
is_determinist = 2;
4325
if (res != 0)
4326
is_determinist = -1;
4327
} else {
4328
is_determinist = -1;
4329
}
4330
tmp++;
4331
}
4332
} else {
4333
is_determinist = 0;
4334
}
4335
}
4336
partitions->groups = groups;
4337
4338
/*
4339
* and save the partition list back in the def
4340
*/
4341
def->data = partitions;
4342
if (is_mixed != 0)
4343
def->dflags |= IS_MIXED;
4344
if (is_determinist == 1)
4345
partitions->flags = IS_DETERMINIST;
4346
if (is_determinist == 2)
4347
partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
4348
return;
4349
4350
error:
4351
xmlRngPErrMemory(ctxt, "in interleave computation\n");
4352
if (groups != NULL) {
4353
for (i = 0; i < nbgroups; i++)
4354
if (groups[i] != NULL) {
4355
if (groups[i]->defs != NULL)
4356
xmlFree(groups[i]->defs);
4357
xmlFree(groups[i]);
4358
}
4359
xmlFree(groups);
4360
}
4361
xmlRelaxNGFreePartition(partitions);
4362
}
4363
4364
/**
4365
* xmlRelaxNGParseInterleave:
4366
* @ctxt: a Relax-NG parser context
4367
* @node: the data node.
4368
*
4369
* parse the content of a RelaxNG interleave node.
4370
*
4371
* Returns the definition pointer or NULL in case of error
4372
*/
4373
static xmlRelaxNGDefinePtr
4374
xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4375
{
4376
xmlRelaxNGDefinePtr def = NULL;
4377
xmlRelaxNGDefinePtr last = NULL, cur;
4378
xmlNodePtr child;
4379
4380
def = xmlRelaxNGNewDefine(ctxt, node);
4381
if (def == NULL) {
4382
return (NULL);
4383
}
4384
def->type = XML_RELAXNG_INTERLEAVE;
4385
4386
if (ctxt->interleaves == NULL)
4387
ctxt->interleaves = xmlHashCreate(10);
4388
if (ctxt->interleaves == NULL) {
4389
xmlRngPErrMemory(ctxt, "create interleaves\n");
4390
} else {
4391
char name[32];
4392
4393
snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4394
if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4395
xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4396
"Failed to add %s to hash table\n",
4397
(const xmlChar *) name, NULL);
4398
}
4399
}
4400
child = node->children;
4401
if (child == NULL) {
4402
xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4403
"Element interleave is empty\n", NULL, NULL);
4404
}
4405
while (child != NULL) {
4406
if (IS_RELAXNG(child, "element")) {
4407
cur = xmlRelaxNGParseElement(ctxt, child);
4408
} else {
4409
cur = xmlRelaxNGParsePattern(ctxt, child);
4410
}
4411
if (cur != NULL) {
4412
cur->parent = def;
4413
if (last == NULL) {
4414
def->content = last = cur;
4415
} else {
4416
last->next = cur;
4417
last = cur;
4418
}
4419
}
4420
child = child->next;
4421
}
4422
4423
return (def);
4424
}
4425
4426
/**
4427
* xmlRelaxNGParseInclude:
4428
* @ctxt: a Relax-NG parser context
4429
* @node: the include node
4430
*
4431
* Integrate the content of an include node in the current grammar
4432
*
4433
* Returns 0 in case of success or -1 in case of error
4434
*/
4435
static int
4436
xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4437
{
4438
xmlRelaxNGIncludePtr incl;
4439
xmlNodePtr root;
4440
int ret = 0, tmp;
4441
4442
incl = node->psvi;
4443
if (incl == NULL) {
4444
xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4445
"Include node has no data\n", NULL, NULL);
4446
return (-1);
4447
}
4448
root = xmlDocGetRootElement(incl->doc);
4449
if (root == NULL) {
4450
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4451
NULL, NULL);
4452
return (-1);
4453
}
4454
if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4455
xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4456
"Include document root is not a grammar\n", NULL, NULL);
4457
return (-1);
4458
}
4459
4460
/*
4461
* Merge the definition from both the include and the internal list
4462
*/
4463
if (root->children != NULL) {
4464
tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4465
if (tmp != 0)
4466
ret = -1;
4467
}
4468
if (node->children != NULL) {
4469
tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4470
if (tmp != 0)
4471
ret = -1;
4472
}
4473
return (ret);
4474
}
4475
4476
/**
4477
* xmlRelaxNGParseDefine:
4478
* @ctxt: a Relax-NG parser context
4479
* @node: the define node
4480
*
4481
* parse the content of a RelaxNG define element node.
4482
*
4483
* Returns 0 in case of success or -1 in case of error
4484
*/
4485
static int
4486
xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4487
{
4488
xmlChar *name;
4489
int ret = 0, tmp;
4490
xmlRelaxNGDefinePtr def;
4491
const xmlChar *olddefine;
4492
4493
name = xmlGetProp(node, BAD_CAST "name");
4494
if (name == NULL) {
4495
xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4496
"define has no name\n", NULL, NULL);
4497
} else {
4498
xmlRelaxNGNormExtSpace(name);
4499
if (xmlValidateNCName(name, 0)) {
4500
xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4501
"define name '%s' is not an NCName\n", name, NULL);
4502
}
4503
def = xmlRelaxNGNewDefine(ctxt, node);
4504
if (def == NULL) {
4505
xmlFree(name);
4506
return (-1);
4507
}
4508
def->type = XML_RELAXNG_DEF;
4509
def->name = name;
4510
if (node->children == NULL) {
4511
xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4512
"define has no children\n", NULL, NULL);
4513
} else {
4514
olddefine = ctxt->define;
4515
ctxt->define = name;
4516
def->content =
4517
xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4518
ctxt->define = olddefine;
4519
}
4520
if (ctxt->grammar->defs == NULL)
4521
ctxt->grammar->defs = xmlHashCreate(10);
4522
if (ctxt->grammar->defs == NULL) {
4523
xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4524
"Could not create definition hash\n", NULL, NULL);
4525
ret = -1;
4526
} else {
4527
tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4528
if (tmp < 0) {
4529
xmlRelaxNGDefinePtr prev;
4530
4531
prev = xmlHashLookup(ctxt->grammar->defs, name);
4532
if (prev == NULL) {
4533
xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4534
"Internal error on define aggregation of %s\n",
4535
name, NULL);
4536
ret = -1;
4537
} else {
4538
while (prev->nextHash != NULL)
4539
prev = prev->nextHash;
4540
prev->nextHash = def;
4541
}
4542
}
4543
}
4544
}
4545
return (ret);
4546
}
4547
4548
/**
4549
* xmlRelaxNGParseImportRef:
4550
* @payload: the parser context
4551
* @data: the current grammar
4552
* @name: the reference name
4553
*
4554
* Import import one references into the current grammar
4555
*/
4556
static void
4557
xmlRelaxNGParseImportRef(void *payload, void *data, const xmlChar *name) {
4558
xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4559
xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4560
int tmp;
4561
4562
def->dflags |= IS_EXTERNAL_REF;
4563
4564
tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
4565
if (tmp < 0) {
4566
xmlRelaxNGDefinePtr prev;
4567
4568
prev = (xmlRelaxNGDefinePtr)
4569
xmlHashLookup(ctxt->grammar->refs, def->name);
4570
if (prev == NULL) {
4571
if (def->name != NULL) {
4572
xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4573
"Error refs definitions '%s'\n",
4574
def->name, NULL);
4575
} else {
4576
xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4577
"Error refs definitions\n",
4578
NULL, NULL);
4579
}
4580
} else {
4581
def->nextHash = prev->nextHash;
4582
prev->nextHash = def;
4583
}
4584
}
4585
}
4586
4587
/**
4588
* xmlRelaxNGParseImportRefs:
4589
* @ctxt: the parser context
4590
* @grammar: the sub grammar
4591
*
4592
* Import references from the subgrammar into the current grammar
4593
*
4594
* Returns 0 in case of success, -1 in case of failure
4595
*/
4596
static int
4597
xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
4598
xmlRelaxNGGrammarPtr grammar) {
4599
if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
4600
return(-1);
4601
if (grammar->refs == NULL)
4602
return(0);
4603
if (ctxt->grammar->refs == NULL)
4604
ctxt->grammar->refs = xmlHashCreate(10);
4605
if (ctxt->grammar->refs == NULL) {
4606
xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4607
"Could not create references hash\n", NULL, NULL);
4608
return(-1);
4609
}
4610
xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
4611
return(0);
4612
}
4613
4614
/**
4615
* xmlRelaxNGProcessExternalRef:
4616
* @ctxt: the parser context
4617
* @node: the externalRef node
4618
*
4619
* Process and compile an externalRef node
4620
*
4621
* Returns the xmlRelaxNGDefinePtr or NULL in case of error
4622
*/
4623
static xmlRelaxNGDefinePtr
4624
xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4625
{
4626
xmlRelaxNGDocumentPtr docu;
4627
xmlNodePtr root, tmp;
4628
xmlChar *ns;
4629
int newNs = 0, oldflags;
4630
xmlRelaxNGDefinePtr def;
4631
4632
docu = node->psvi;
4633
if (docu != NULL) {
4634
def = xmlRelaxNGNewDefine(ctxt, node);
4635
if (def == NULL)
4636
return (NULL);
4637
def->type = XML_RELAXNG_EXTERNALREF;
4638
4639
if (docu->content == NULL) {
4640
/*
4641
* Then do the parsing for good
4642
*/
4643
root = xmlDocGetRootElement(docu->doc);
4644
if (root == NULL) {
4645
xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
4646
"xmlRelaxNGParse: %s is empty\n", ctxt->URL,
4647
NULL);
4648
return (NULL);
4649
}
4650
/*
4651
* ns transmission rules
4652
*/
4653
ns = xmlGetProp(root, BAD_CAST "ns");
4654
if (ns == NULL) {
4655
tmp = node;
4656
while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
4657
ns = xmlGetProp(tmp, BAD_CAST "ns");
4658
if (ns != NULL) {
4659
break;
4660
}
4661
tmp = tmp->parent;
4662
}
4663
if (ns != NULL) {
4664
xmlSetProp(root, BAD_CAST "ns", ns);
4665
newNs = 1;
4666
xmlFree(ns);
4667
}
4668
} else {
4669
xmlFree(ns);
4670
}
4671
4672
/*
4673
* Parsing to get a precompiled schemas.
4674
*/
4675
oldflags = ctxt->flags;
4676
ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
4677
docu->schema = xmlRelaxNGParseDocument(ctxt, root);
4678
ctxt->flags = oldflags;
4679
if ((docu->schema != NULL) &&
4680
(docu->schema->topgrammar != NULL)) {
4681
docu->content = docu->schema->topgrammar->start;
4682
if (docu->schema->topgrammar->refs)
4683
xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
4684
}
4685
4686
/*
4687
* the externalRef may be reused in a different ns context
4688
*/
4689
if (newNs == 1) {
4690
xmlUnsetProp(root, BAD_CAST "ns");
4691
}
4692
}
4693
def->content = docu->content;
4694
} else {
4695
def = NULL;
4696
}
4697
return (def);
4698
}
4699
4700
/**
4701
* xmlRelaxNGParsePattern:
4702
* @ctxt: a Relax-NG parser context
4703
* @node: the pattern node.
4704
*
4705
* parse the content of a RelaxNG pattern node.
4706
*
4707
* Returns the definition pointer or NULL in case of error or if no
4708
* pattern is generated.
4709
*/
4710
static xmlRelaxNGDefinePtr
4711
xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4712
{
4713
xmlRelaxNGDefinePtr def = NULL;
4714
4715
if (node == NULL) {
4716
return (NULL);
4717
}
4718
if (IS_RELAXNG(node, "element")) {
4719
def = xmlRelaxNGParseElement(ctxt, node);
4720
} else if (IS_RELAXNG(node, "attribute")) {
4721
def = xmlRelaxNGParseAttribute(ctxt, node);
4722
} else if (IS_RELAXNG(node, "empty")) {
4723
def = xmlRelaxNGNewDefine(ctxt, node);
4724
if (def == NULL)
4725
return (NULL);
4726
def->type = XML_RELAXNG_EMPTY;
4727
if (node->children != NULL) {
4728
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
4729
"empty: had a child node\n", NULL, NULL);
4730
}
4731
} else if (IS_RELAXNG(node, "text")) {
4732
def = xmlRelaxNGNewDefine(ctxt, node);
4733
if (def == NULL)
4734
return (NULL);
4735
def->type = XML_RELAXNG_TEXT;
4736
if (node->children != NULL) {
4737
xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
4738
"text: had a child node\n", NULL, NULL);
4739
}
4740
} else if (IS_RELAXNG(node, "zeroOrMore")) {
4741
def = xmlRelaxNGNewDefine(ctxt, node);
4742
if (def == NULL)
4743
return (NULL);
4744
def->type = XML_RELAXNG_ZEROORMORE;
4745
if (node->children == NULL) {
4746
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4747
"Element %s is empty\n", node->name, NULL);
4748
} else {
4749
def->content =
4750
xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4751
}
4752
} else if (IS_RELAXNG(node, "oneOrMore")) {
4753
def = xmlRelaxNGNewDefine(ctxt, node);
4754
if (def == NULL)
4755
return (NULL);
4756
def->type = XML_RELAXNG_ONEORMORE;
4757
if (node->children == NULL) {
4758
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4759
"Element %s is empty\n", node->name, NULL);
4760
} else {
4761
def->content =
4762
xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4763
}
4764
} else if (IS_RELAXNG(node, "optional")) {
4765
def = xmlRelaxNGNewDefine(ctxt, node);
4766
if (def == NULL)
4767
return (NULL);
4768
def->type = XML_RELAXNG_OPTIONAL;
4769
if (node->children == NULL) {
4770
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4771
"Element %s is empty\n", node->name, NULL);
4772
} else {
4773
def->content =
4774
xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4775
}
4776
} else if (IS_RELAXNG(node, "choice")) {
4777
def = xmlRelaxNGNewDefine(ctxt, node);
4778
if (def == NULL)
4779
return (NULL);
4780
def->type = XML_RELAXNG_CHOICE;
4781
if (node->children == NULL) {
4782
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4783
"Element %s is empty\n", node->name, NULL);
4784
} else {
4785
def->content =
4786
xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4787
}
4788
} else if (IS_RELAXNG(node, "group")) {
4789
def = xmlRelaxNGNewDefine(ctxt, node);
4790
if (def == NULL)
4791
return (NULL);
4792
def->type = XML_RELAXNG_GROUP;
4793
if (node->children == NULL) {
4794
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4795
"Element %s is empty\n", node->name, NULL);
4796
} else {
4797
def->content =
4798
xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4799
}
4800
} else if (IS_RELAXNG(node, "ref")) {
4801
def = xmlRelaxNGNewDefine(ctxt, node);
4802
if (def == NULL)
4803
return (NULL);
4804
def->type = XML_RELAXNG_REF;
4805
def->name = xmlGetProp(node, BAD_CAST "name");
4806
if (def->name == NULL) {
4807
xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
4808
NULL, NULL);
4809
} else {
4810
xmlRelaxNGNormExtSpace(def->name);
4811
if (xmlValidateNCName(def->name, 0)) {
4812
xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
4813
"ref name '%s' is not an NCName\n", def->name,
4814
NULL);
4815
}
4816
}
4817
if (node->children != NULL) {
4818
xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
4819
NULL, NULL);
4820
}
4821
if (ctxt->grammar->refs == NULL)
4822
ctxt->grammar->refs = xmlHashCreate(10);
4823
if (ctxt->grammar->refs == NULL) {
4824
xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4825
"Could not create references hash\n", NULL, NULL);
4826
def = NULL;
4827
} else {
4828
int tmp;
4829
4830
tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4831
if (tmp < 0) {
4832
xmlRelaxNGDefinePtr prev;
4833
4834
prev = (xmlRelaxNGDefinePtr)
4835
xmlHashLookup(ctxt->grammar->refs, def->name);
4836
if (prev == NULL) {
4837
if (def->name != NULL) {
4838
xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4839
"Error refs definitions '%s'\n",
4840
def->name, NULL);
4841
} else {
4842
xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
4843
"Error refs definitions\n",
4844
NULL, NULL);
4845
}
4846
def = NULL;
4847
} else {
4848
def->nextHash = prev->nextHash;
4849
prev->nextHash = def;
4850
}
4851
}
4852
}
4853
} else if (IS_RELAXNG(node, "data")) {
4854
def = xmlRelaxNGParseData(ctxt, node);
4855
} else if (IS_RELAXNG(node, "value")) {
4856
def = xmlRelaxNGParseValue(ctxt, node);
4857
} else if (IS_RELAXNG(node, "list")) {
4858
def = xmlRelaxNGNewDefine(ctxt, node);
4859
if (def == NULL)
4860
return (NULL);
4861
def->type = XML_RELAXNG_LIST;
4862
if (node->children == NULL) {
4863
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
4864
"Element %s is empty\n", node->name, NULL);
4865
} else {
4866
def->content =
4867
xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4868
}
4869
} else if (IS_RELAXNG(node, "interleave")) {
4870
def = xmlRelaxNGParseInterleave(ctxt, node);
4871
} else if (IS_RELAXNG(node, "externalRef")) {
4872
def = xmlRelaxNGProcessExternalRef(ctxt, node);
4873
} else if (IS_RELAXNG(node, "notAllowed")) {
4874
def = xmlRelaxNGNewDefine(ctxt, node);
4875
if (def == NULL)
4876
return (NULL);
4877
def->type = XML_RELAXNG_NOT_ALLOWED;
4878
if (node->children != NULL) {
4879
xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
4880
"xmlRelaxNGParse: notAllowed element is not empty\n",
4881
NULL, NULL);
4882
}
4883
} else if (IS_RELAXNG(node, "grammar")) {
4884
xmlRelaxNGGrammarPtr grammar, old;
4885
xmlRelaxNGGrammarPtr oldparent;
4886
4887
oldparent = ctxt->parentgrammar;
4888
old = ctxt->grammar;
4889
ctxt->parentgrammar = old;
4890
grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4891
if (old != NULL) {
4892
ctxt->grammar = old;
4893
ctxt->parentgrammar = oldparent;
4894
#if 0
4895
if (grammar != NULL) {
4896
grammar->next = old->next;
4897
old->next = grammar;
4898
}
4899
#endif
4900
}
4901
if (grammar != NULL)
4902
def = grammar->start;
4903
else
4904
def = NULL;
4905
} else if (IS_RELAXNG(node, "parentRef")) {
4906
if (ctxt->parentgrammar == NULL) {
4907
xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
4908
"Use of parentRef without a parent grammar\n", NULL,
4909
NULL);
4910
return (NULL);
4911
}
4912
def = xmlRelaxNGNewDefine(ctxt, node);
4913
if (def == NULL)
4914
return (NULL);
4915
def->type = XML_RELAXNG_PARENTREF;
4916
def->name = xmlGetProp(node, BAD_CAST "name");
4917
if (def->name == NULL) {
4918
xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
4919
"parentRef has no name\n", NULL, NULL);
4920
} else {
4921
xmlRelaxNGNormExtSpace(def->name);
4922
if (xmlValidateNCName(def->name, 0)) {
4923
xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
4924
"parentRef name '%s' is not an NCName\n",
4925
def->name, NULL);
4926
}
4927
}
4928
if (node->children != NULL) {
4929
xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
4930
"parentRef is not empty\n", NULL, NULL);
4931
}
4932
if (ctxt->parentgrammar->refs == NULL)
4933
ctxt->parentgrammar->refs = xmlHashCreate(10);
4934
if (ctxt->parentgrammar->refs == NULL) {
4935
xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4936
"Could not create references hash\n", NULL, NULL);
4937
def = NULL;
4938
} else if (def->name != NULL) {
4939
int tmp;
4940
4941
tmp =
4942
xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4943
if (tmp < 0) {
4944
xmlRelaxNGDefinePtr prev;
4945
4946
prev = (xmlRelaxNGDefinePtr)
4947
xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4948
if (prev == NULL) {
4949
xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
4950
"Internal error parentRef definitions '%s'\n",
4951
def->name, NULL);
4952
def = NULL;
4953
} else {
4954
def->nextHash = prev->nextHash;
4955
prev->nextHash = def;
4956
}
4957
}
4958
}
4959
} else if (IS_RELAXNG(node, "mixed")) {
4960
if (node->children == NULL) {
4961
xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
4962
NULL, NULL);
4963
def = NULL;
4964
} else {
4965
def = xmlRelaxNGParseInterleave(ctxt, node);
4966
if (def != NULL) {
4967
xmlRelaxNGDefinePtr tmp;
4968
4969
if ((def->content != NULL) && (def->content->next != NULL)) {
4970
tmp = xmlRelaxNGNewDefine(ctxt, node);
4971
if (tmp != NULL) {
4972
tmp->type = XML_RELAXNG_GROUP;
4973
tmp->content = def->content;
4974
def->content = tmp;
4975
}
4976
}
4977
4978
tmp = xmlRelaxNGNewDefine(ctxt, node);
4979
if (tmp == NULL)
4980
return (def);
4981
tmp->type = XML_RELAXNG_TEXT;
4982
tmp->next = def->content;
4983
def->content = tmp;
4984
}
4985
}
4986
} else {
4987
xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
4988
"Unexpected node %s is not a pattern\n", node->name,
4989
NULL);
4990
def = NULL;
4991
}
4992
return (def);
4993
}
4994
4995
/**
4996
* xmlRelaxNGParseAttribute:
4997
* @ctxt: a Relax-NG parser context
4998
* @node: the element node
4999
*
5000
* parse the content of a RelaxNG attribute node.
5001
*
5002
* Returns the definition pointer or NULL in case of error.
5003
*/
5004
static xmlRelaxNGDefinePtr
5005
xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5006
{
5007
xmlRelaxNGDefinePtr ret, cur;
5008
xmlNodePtr child;
5009
int old_flags;
5010
5011
ret = xmlRelaxNGNewDefine(ctxt, node);
5012
if (ret == NULL)
5013
return (NULL);
5014
ret->type = XML_RELAXNG_ATTRIBUTE;
5015
ret->parent = ctxt->def;
5016
child = node->children;
5017
if (child == NULL) {
5018
xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
5019
"xmlRelaxNGParseattribute: attribute has no children\n",
5020
NULL, NULL);
5021
return (ret);
5022
}
5023
old_flags = ctxt->flags;
5024
ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
5025
cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5026
if (cur != NULL)
5027
child = child->next;
5028
5029
if (child != NULL) {
5030
cur = xmlRelaxNGParsePattern(ctxt, child);
5031
if (cur != NULL) {
5032
switch (cur->type) {
5033
case XML_RELAXNG_EMPTY:
5034
case XML_RELAXNG_NOT_ALLOWED:
5035
case XML_RELAXNG_TEXT:
5036
case XML_RELAXNG_ELEMENT:
5037
case XML_RELAXNG_DATATYPE:
5038
case XML_RELAXNG_VALUE:
5039
case XML_RELAXNG_LIST:
5040
case XML_RELAXNG_REF:
5041
case XML_RELAXNG_PARENTREF:
5042
case XML_RELAXNG_EXTERNALREF:
5043
case XML_RELAXNG_DEF:
5044
case XML_RELAXNG_ONEORMORE:
5045
case XML_RELAXNG_ZEROORMORE:
5046
case XML_RELAXNG_OPTIONAL:
5047
case XML_RELAXNG_CHOICE:
5048
case XML_RELAXNG_GROUP:
5049
case XML_RELAXNG_INTERLEAVE:
5050
case XML_RELAXNG_ATTRIBUTE:
5051
ret->content = cur;
5052
cur->parent = ret;
5053
break;
5054
case XML_RELAXNG_START:
5055
case XML_RELAXNG_PARAM:
5056
case XML_RELAXNG_EXCEPT:
5057
xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
5058
"attribute has invalid content\n", NULL,
5059
NULL);
5060
break;
5061
case XML_RELAXNG_NOOP:
5062
xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
5063
"RNG Internal error, noop found in attribute\n",
5064
NULL, NULL);
5065
break;
5066
}
5067
}
5068
child = child->next;
5069
}
5070
if (child != NULL) {
5071
xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
5072
"attribute has multiple children\n", NULL, NULL);
5073
}
5074
ctxt->flags = old_flags;
5075
return (ret);
5076
}
5077
5078
/**
5079
* xmlRelaxNGParseExceptNameClass:
5080
* @ctxt: a Relax-NG parser context
5081
* @node: the except node
5082
* @attr: 1 if within an attribute, 0 if within an element
5083
*
5084
* parse the content of a RelaxNG nameClass node.
5085
*
5086
* Returns the definition pointer or NULL in case of error.
5087
*/
5088
static xmlRelaxNGDefinePtr
5089
xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
5090
xmlNodePtr node, int attr)
5091
{
5092
xmlRelaxNGDefinePtr ret, cur, last = NULL;
5093
xmlNodePtr child;
5094
5095
if (!IS_RELAXNG(node, "except")) {
5096
xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
5097
"Expecting an except node\n", NULL, NULL);
5098
return (NULL);
5099
}
5100
if (node->next != NULL) {
5101
xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
5102
"exceptNameClass allows only a single except node\n",
5103
NULL, NULL);
5104
}
5105
if (node->children == NULL) {
5106
xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
5107
NULL, NULL);
5108
return (NULL);
5109
}
5110
5111
ret = xmlRelaxNGNewDefine(ctxt, node);
5112
if (ret == NULL)
5113
return (NULL);
5114
ret->type = XML_RELAXNG_EXCEPT;
5115
child = node->children;
5116
while (child != NULL) {
5117
cur = xmlRelaxNGNewDefine(ctxt, child);
5118
if (cur == NULL)
5119
break;
5120
if (attr)
5121
cur->type = XML_RELAXNG_ATTRIBUTE;
5122
else
5123
cur->type = XML_RELAXNG_ELEMENT;
5124
5125
if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
5126
if (last == NULL) {
5127
ret->content = cur;
5128
} else {
5129
last->next = cur;
5130
}
5131
last = cur;
5132
}
5133
child = child->next;
5134
}
5135
5136
return (ret);
5137
}
5138
5139
/**
5140
* xmlRelaxNGParseNameClass:
5141
* @ctxt: a Relax-NG parser context
5142
* @node: the nameClass node
5143
* @def: the current definition
5144
*
5145
* parse the content of a RelaxNG nameClass node.
5146
*
5147
* Returns the definition pointer or NULL in case of error.
5148
*/
5149
static xmlRelaxNGDefinePtr
5150
xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
5151
xmlRelaxNGDefinePtr def)
5152
{
5153
xmlRelaxNGDefinePtr ret, tmp;
5154
xmlChar *val;
5155
5156
ret = def;
5157
if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
5158
(IS_RELAXNG(node, "nsName"))) {
5159
if ((def->type != XML_RELAXNG_ELEMENT) &&
5160
(def->type != XML_RELAXNG_ATTRIBUTE)) {
5161
ret = xmlRelaxNGNewDefine(ctxt, node);
5162
if (ret == NULL)
5163
return (NULL);
5164
ret->parent = def;
5165
if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
5166
ret->type = XML_RELAXNG_ATTRIBUTE;
5167
else
5168
ret->type = XML_RELAXNG_ELEMENT;
5169
}
5170
}
5171
if (IS_RELAXNG(node, "name")) {
5172
val = xmlNodeGetContent(node);
5173
xmlRelaxNGNormExtSpace(val);
5174
if (xmlValidateNCName(val, 0)) {
5175
if (node->parent != NULL)
5176
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5177
"Element %s name '%s' is not an NCName\n",
5178
node->parent->name, val);
5179
else
5180
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
5181
"name '%s' is not an NCName\n",
5182
val, NULL);
5183
}
5184
ret->name = val;
5185
val = xmlGetProp(node, BAD_CAST "ns");
5186
ret->ns = val;
5187
if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5188
(val != NULL) &&
5189
(xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5190
xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5191
"Attribute with namespace '%s' is not allowed\n",
5192
val, NULL);
5193
}
5194
if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5195
(val != NULL) &&
5196
(val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5197
xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
5198
"Attribute with QName 'xmlns' is not allowed\n",
5199
val, NULL);
5200
}
5201
} else if (IS_RELAXNG(node, "anyName")) {
5202
ret->name = NULL;
5203
ret->ns = NULL;
5204
if (node->children != NULL) {
5205
ret->nameClass =
5206
xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5207
(def->type ==
5208
XML_RELAXNG_ATTRIBUTE));
5209
}
5210
} else if (IS_RELAXNG(node, "nsName")) {
5211
ret->name = NULL;
5212
ret->ns = xmlGetProp(node, BAD_CAST "ns");
5213
if (ret->ns == NULL) {
5214
xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
5215
"nsName has no ns attribute\n", NULL, NULL);
5216
}
5217
if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5218
(ret->ns != NULL) &&
5219
(xmlStrEqual
5220
(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5221
xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
5222
"Attribute with namespace '%s' is not allowed\n",
5223
ret->ns, NULL);
5224
}
5225
if (node->children != NULL) {
5226
ret->nameClass =
5227
xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5228
(def->type ==
5229
XML_RELAXNG_ATTRIBUTE));
5230
}
5231
} else if (IS_RELAXNG(node, "choice")) {
5232
xmlNodePtr child;
5233
xmlRelaxNGDefinePtr last = NULL;
5234
5235
if (def->type == XML_RELAXNG_CHOICE) {
5236
ret = def;
5237
} else {
5238
ret = xmlRelaxNGNewDefine(ctxt, node);
5239
if (ret == NULL)
5240
return (NULL);
5241
ret->parent = def;
5242
ret->type = XML_RELAXNG_CHOICE;
5243
}
5244
5245
if (node->children == NULL) {
5246
xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
5247
"Element choice is empty\n", NULL, NULL);
5248
} else {
5249
5250
child = node->children;
5251
while (child != NULL) {
5252
tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5253
if (tmp != NULL) {
5254
if (last == NULL) {
5255
last = tmp;
5256
} else {
5257
last->next = tmp;
5258
last = tmp;
5259
}
5260
}
5261
child = child->next;
5262
}
5263
}
5264
} else {
5265
xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
5266
"expecting name, anyName, nsName or choice : got %s\n",
5267
(node == NULL ? (const xmlChar *) "nothing" : node->name),
5268
NULL);
5269
return (NULL);
5270
}
5271
if (ret != def) {
5272
if (def->nameClass == NULL) {
5273
def->nameClass = ret;
5274
} else {
5275
tmp = def->nameClass;
5276
while (tmp->next != NULL) {
5277
tmp = tmp->next;
5278
}
5279
tmp->next = ret;
5280
}
5281
}
5282
return (ret);
5283
}
5284
5285
/**
5286
* xmlRelaxNGParseElement:
5287
* @ctxt: a Relax-NG parser context
5288
* @node: the element node
5289
*
5290
* parse the content of a RelaxNG element node.
5291
*
5292
* Returns the definition pointer or NULL in case of error.
5293
*/
5294
static xmlRelaxNGDefinePtr
5295
xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
5296
{
5297
xmlRelaxNGDefinePtr ret, cur, last;
5298
xmlNodePtr child;
5299
const xmlChar *olddefine;
5300
5301
ret = xmlRelaxNGNewDefine(ctxt, node);
5302
if (ret == NULL)
5303
return (NULL);
5304
ret->type = XML_RELAXNG_ELEMENT;
5305
ret->parent = ctxt->def;
5306
child = node->children;
5307
if (child == NULL) {
5308
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
5309
"xmlRelaxNGParseElement: element has no children\n",
5310
NULL, NULL);
5311
return (ret);
5312
}
5313
cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5314
if (cur != NULL)
5315
child = child->next;
5316
5317
if (child == NULL) {
5318
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
5319
"xmlRelaxNGParseElement: element has no content\n",
5320
NULL, NULL);
5321
return (ret);
5322
}
5323
olddefine = ctxt->define;
5324
ctxt->define = NULL;
5325
last = NULL;
5326
while (child != NULL) {
5327
cur = xmlRelaxNGParsePattern(ctxt, child);
5328
if (cur != NULL) {
5329
cur->parent = ret;
5330
switch (cur->type) {
5331
case XML_RELAXNG_EMPTY:
5332
case XML_RELAXNG_NOT_ALLOWED:
5333
case XML_RELAXNG_TEXT:
5334
case XML_RELAXNG_ELEMENT:
5335
case XML_RELAXNG_DATATYPE:
5336
case XML_RELAXNG_VALUE:
5337
case XML_RELAXNG_LIST:
5338
case XML_RELAXNG_REF:
5339
case XML_RELAXNG_PARENTREF:
5340
case XML_RELAXNG_EXTERNALREF:
5341
case XML_RELAXNG_DEF:
5342
case XML_RELAXNG_ZEROORMORE:
5343
case XML_RELAXNG_ONEORMORE:
5344
case XML_RELAXNG_OPTIONAL:
5345
case XML_RELAXNG_CHOICE:
5346
case XML_RELAXNG_GROUP:
5347
case XML_RELAXNG_INTERLEAVE:
5348
if (last == NULL) {
5349
ret->content = last = cur;
5350
} else {
5351
if ((last->type == XML_RELAXNG_ELEMENT) &&
5352
(ret->content == last)) {
5353
ret->content = xmlRelaxNGNewDefine(ctxt, node);
5354
if (ret->content != NULL) {
5355
ret->content->type = XML_RELAXNG_GROUP;
5356
ret->content->content = last;
5357
} else {
5358
ret->content = last;
5359
}
5360
}
5361
last->next = cur;
5362
last = cur;
5363
}
5364
break;
5365
case XML_RELAXNG_ATTRIBUTE:
5366
cur->next = ret->attrs;
5367
ret->attrs = cur;
5368
break;
5369
case XML_RELAXNG_START:
5370
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5371
"RNG Internal error, start found in element\n",
5372
NULL, NULL);
5373
break;
5374
case XML_RELAXNG_PARAM:
5375
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5376
"RNG Internal error, param found in element\n",
5377
NULL, NULL);
5378
break;
5379
case XML_RELAXNG_EXCEPT:
5380
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5381
"RNG Internal error, except found in element\n",
5382
NULL, NULL);
5383
break;
5384
case XML_RELAXNG_NOOP:
5385
xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
5386
"RNG Internal error, noop found in element\n",
5387
NULL, NULL);
5388
break;
5389
}
5390
}
5391
child = child->next;
5392
}
5393
ctxt->define = olddefine;
5394
return (ret);
5395
}
5396
5397
/**
5398
* xmlRelaxNGParsePatterns:
5399
* @ctxt: a Relax-NG parser context
5400
* @nodes: list of nodes
5401
* @group: use an implicit <group> for elements
5402
*
5403
* parse the content of a RelaxNG start node.
5404
*
5405
* Returns the definition pointer or NULL in case of error.
5406
*/
5407
static xmlRelaxNGDefinePtr
5408
xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5409
int group)
5410
{
5411
xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
5412
5413
parent = ctxt->def;
5414
while (nodes != NULL) {
5415
if (IS_RELAXNG(nodes, "element")) {
5416
cur = xmlRelaxNGParseElement(ctxt, nodes);
5417
if (cur == NULL)
5418
return (NULL);
5419
if (def == NULL) {
5420
def = last = cur;
5421
} else {
5422
if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5423
(def == last)) {
5424
def = xmlRelaxNGNewDefine(ctxt, nodes);
5425
if (def == NULL)
5426
return (NULL);
5427
def->type = XML_RELAXNG_GROUP;
5428
def->content = last;
5429
}
5430
last->next = cur;
5431
last = cur;
5432
}
5433
cur->parent = parent;
5434
} else {
5435
cur = xmlRelaxNGParsePattern(ctxt, nodes);
5436
if (cur != NULL) {
5437
if (def == NULL) {
5438
def = last = cur;
5439
} else {
5440
last->next = cur;
5441
last = cur;
5442
}
5443
}
5444
}
5445
nodes = nodes->next;
5446
}
5447
return (def);
5448
}
5449
5450
/**
5451
* xmlRelaxNGParseStart:
5452
* @ctxt: a Relax-NG parser context
5453
* @nodes: start children nodes
5454
*
5455
* parse the content of a RelaxNG start node.
5456
*
5457
* Returns 0 in case of success, -1 in case of error
5458
*/
5459
static int
5460
xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
5461
{
5462
int ret = 0;
5463
xmlRelaxNGDefinePtr def = NULL, last;
5464
5465
if (nodes == NULL) {
5466
xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
5467
NULL, NULL);
5468
return (-1);
5469
}
5470
if (IS_RELAXNG(nodes, "empty")) {
5471
def = xmlRelaxNGNewDefine(ctxt, nodes);
5472
if (def == NULL)
5473
return (-1);
5474
def->type = XML_RELAXNG_EMPTY;
5475
if (nodes->children != NULL) {
5476
xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
5477
"element empty is not empty\n", NULL, NULL);
5478
}
5479
} else if (IS_RELAXNG(nodes, "notAllowed")) {
5480
def = xmlRelaxNGNewDefine(ctxt, nodes);
5481
if (def == NULL)
5482
return (-1);
5483
def->type = XML_RELAXNG_NOT_ALLOWED;
5484
if (nodes->children != NULL) {
5485
xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
5486
"element notAllowed is not empty\n", NULL, NULL);
5487
}
5488
} else {
5489
def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
5490
}
5491
if (ctxt->grammar->start != NULL) {
5492
last = ctxt->grammar->start;
5493
while (last->next != NULL)
5494
last = last->next;
5495
last->next = def;
5496
} else {
5497
ctxt->grammar->start = def;
5498
}
5499
nodes = nodes->next;
5500
if (nodes != NULL) {
5501
xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
5502
"start more than one children\n", NULL, NULL);
5503
return (-1);
5504
}
5505
return (ret);
5506
}
5507
5508
/**
5509
* xmlRelaxNGParseGrammarContent:
5510
* @ctxt: a Relax-NG parser context
5511
* @nodes: grammar children nodes
5512
*
5513
* parse the content of a RelaxNG grammar node.
5514
*
5515
* Returns 0 in case of success, -1 in case of error
5516
*/
5517
static int
5518
xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
5519
xmlNodePtr nodes)
5520
{
5521
int ret = 0, tmp;
5522
5523
if (nodes == NULL) {
5524
xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
5525
"grammar has no children\n", NULL, NULL);
5526
return (-1);
5527
}
5528
while (nodes != NULL) {
5529
if (IS_RELAXNG(nodes, "start")) {
5530
if (nodes->children == NULL) {
5531
xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
5532
"start has no children\n", NULL, NULL);
5533
} else {
5534
tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5535
if (tmp != 0)
5536
ret = -1;
5537
}
5538
} else if (IS_RELAXNG(nodes, "define")) {
5539
tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5540
if (tmp != 0)
5541
ret = -1;
5542
} else if (IS_RELAXNG(nodes, "include")) {
5543
tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5544
if (tmp != 0)
5545
ret = -1;
5546
} else {
5547
xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
5548
"grammar has unexpected child %s\n", nodes->name,
5549
NULL);
5550
ret = -1;
5551
}
5552
nodes = nodes->next;
5553
}
5554
return (ret);
5555
}
5556
5557
/**
5558
* xmlRelaxNGCheckReference:
5559
* @ref: the ref
5560
* @ctxt: a Relax-NG parser context
5561
* @name: the name associated to the defines
5562
*
5563
* Applies the 4.17. combine attribute rule for all the define
5564
* element of a given grammar using the same name.
5565
*/
5566
static void
5567
xmlRelaxNGCheckReference(void *payload, void *data, const xmlChar * name)
5568
{
5569
xmlRelaxNGDefinePtr ref = (xmlRelaxNGDefinePtr) payload;
5570
xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
5571
xmlRelaxNGGrammarPtr grammar;
5572
xmlRelaxNGDefinePtr def, cur;
5573
5574
/*
5575
* Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5576
*/
5577
if (ref->dflags & IS_EXTERNAL_REF)
5578
return;
5579
5580
grammar = ctxt->grammar;
5581
if (grammar == NULL) {
5582
xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5583
"Internal error: no grammar in CheckReference %s\n",
5584
name, NULL);
5585
return;
5586
}
5587
if (ref->content != NULL) {
5588
xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
5589
"Internal error: reference has content in CheckReference %s\n",
5590
name, NULL);
5591
return;
5592
}
5593
if (grammar->defs != NULL) {
5594
def = xmlHashLookup(grammar->defs, name);
5595
if (def != NULL) {
5596
cur = ref;
5597
while (cur != NULL) {
5598
cur->content = def;
5599
cur = cur->nextHash;
5600
}
5601
} else {
5602
xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5603
"Reference %s has no matching definition\n", name,
5604
NULL);
5605
}
5606
} else {
5607
xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
5608
"Reference %s has no matching definition\n", name,
5609
NULL);
5610
}
5611
}
5612
5613
/**
5614
* xmlRelaxNGCheckCombine:
5615
* @define: the define(s) list
5616
* @ctxt: a Relax-NG parser context
5617
* @name: the name associated to the defines
5618
*
5619
* Applies the 4.17. combine attribute rule for all the define
5620
* element of a given grammar using the same name.
5621
*/
5622
static void
5623
xmlRelaxNGCheckCombine(void *payload, void *data, const xmlChar * name)
5624
{
5625
xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) payload;
5626
xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
5627
xmlChar *combine;
5628
int choiceOrInterleave = -1;
5629
int missing = 0;
5630
xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5631
5632
if (define->nextHash == NULL)
5633
return;
5634
cur = define;
5635
while (cur != NULL) {
5636
combine = xmlGetProp(cur->node, BAD_CAST "combine");
5637
if (combine != NULL) {
5638
if (xmlStrEqual(combine, BAD_CAST "choice")) {
5639
if (choiceOrInterleave == -1)
5640
choiceOrInterleave = 1;
5641
else if (choiceOrInterleave == 0) {
5642
xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5643
"Defines for %s use both 'choice' and 'interleave'\n",
5644
name, NULL);
5645
}
5646
} else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5647
if (choiceOrInterleave == -1)
5648
choiceOrInterleave = 0;
5649
else if (choiceOrInterleave == 1) {
5650
xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
5651
"Defines for %s use both 'choice' and 'interleave'\n",
5652
name, NULL);
5653
}
5654
} else {
5655
xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
5656
"Defines for %s use unknown combine value '%s''\n",
5657
name, combine);
5658
}
5659
xmlFree(combine);
5660
} else {
5661
if (missing == 0)
5662
missing = 1;
5663
else {
5664
xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
5665
"Some defines for %s needs the combine attribute\n",
5666
name, NULL);
5667
}
5668
}
5669
5670
cur = cur->nextHash;
5671
}
5672
if (choiceOrInterleave == -1)
5673
choiceOrInterleave = 0;
5674
cur = xmlRelaxNGNewDefine(ctxt, define->node);
5675
if (cur == NULL)
5676
return;
5677
if (choiceOrInterleave == 0)
5678
cur->type = XML_RELAXNG_INTERLEAVE;
5679
else
5680
cur->type = XML_RELAXNG_CHOICE;
5681
tmp = define;
5682
last = NULL;
5683
while (tmp != NULL) {
5684
if (tmp->content != NULL) {
5685
if (tmp->content->next != NULL) {
5686
/*
5687
* we need first to create a wrapper.
5688
*/
5689
tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
5690
if (tmp2 == NULL)
5691
break;
5692
tmp2->type = XML_RELAXNG_GROUP;
5693
tmp2->content = tmp->content;
5694
} else {
5695
tmp2 = tmp->content;
5696
}
5697
if (last == NULL) {
5698
cur->content = tmp2;
5699
} else {
5700
last->next = tmp2;
5701
}
5702
last = tmp2;
5703
}
5704
tmp->content = cur;
5705
tmp = tmp->nextHash;
5706
}
5707
define->content = cur;
5708
if (choiceOrInterleave == 0) {
5709
if (ctxt->interleaves == NULL)
5710
ctxt->interleaves = xmlHashCreate(10);
5711
if (ctxt->interleaves == NULL) {
5712
xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5713
"Failed to create interleaves hash table\n", NULL,
5714
NULL);
5715
} else {
5716
char tmpname[32];
5717
5718
snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5719
if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5720
0) {
5721
xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5722
"Failed to add %s to hash table\n",
5723
(const xmlChar *) tmpname, NULL);
5724
}
5725
}
5726
}
5727
}
5728
5729
/**
5730
* xmlRelaxNGCombineStart:
5731
* @ctxt: a Relax-NG parser context
5732
* @grammar: the grammar
5733
*
5734
* Applies the 4.17. combine rule for all the start
5735
* element of a given grammar.
5736
*/
5737
static void
5738
xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5739
xmlRelaxNGGrammarPtr grammar)
5740
{
5741
xmlRelaxNGDefinePtr starts;
5742
xmlChar *combine;
5743
int choiceOrInterleave = -1;
5744
int missing = 0;
5745
xmlRelaxNGDefinePtr cur;
5746
5747
starts = grammar->start;
5748
if ((starts == NULL) || (starts->next == NULL))
5749
return;
5750
cur = starts;
5751
while (cur != NULL) {
5752
if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5753
(!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5754
combine = NULL;
5755
xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
5756
"Internal error: start element not found\n", NULL,
5757
NULL);
5758
} else {
5759
combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5760
}
5761
5762
if (combine != NULL) {
5763
if (xmlStrEqual(combine, BAD_CAST "choice")) {
5764
if (choiceOrInterleave == -1)
5765
choiceOrInterleave = 1;
5766
else if (choiceOrInterleave == 0) {
5767
xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5768
"<start> use both 'choice' and 'interleave'\n",
5769
NULL, NULL);
5770
}
5771
} else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
5772
if (choiceOrInterleave == -1)
5773
choiceOrInterleave = 0;
5774
else if (choiceOrInterleave == 1) {
5775
xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
5776
"<start> use both 'choice' and 'interleave'\n",
5777
NULL, NULL);
5778
}
5779
} else {
5780
xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
5781
"<start> uses unknown combine value '%s''\n",
5782
combine, NULL);
5783
}
5784
xmlFree(combine);
5785
} else {
5786
if (missing == 0)
5787
missing = 1;
5788
else {
5789
xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
5790
"Some <start> element miss the combine attribute\n",
5791
NULL, NULL);
5792
}
5793
}
5794
5795
cur = cur->next;
5796
}
5797
if (choiceOrInterleave == -1)
5798
choiceOrInterleave = 0;
5799
cur = xmlRelaxNGNewDefine(ctxt, starts->node);
5800
if (cur == NULL)
5801
return;
5802
if (choiceOrInterleave == 0)
5803
cur->type = XML_RELAXNG_INTERLEAVE;
5804
else
5805
cur->type = XML_RELAXNG_CHOICE;
5806
cur->content = grammar->start;
5807
grammar->start = cur;
5808
if (choiceOrInterleave == 0) {
5809
if (ctxt->interleaves == NULL)
5810
ctxt->interleaves = xmlHashCreate(10);
5811
if (ctxt->interleaves == NULL) {
5812
xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5813
"Failed to create interleaves hash table\n", NULL,
5814
NULL);
5815
} else {
5816
char tmpname[32];
5817
5818
snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5819
if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
5820
0) {
5821
xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
5822
"Failed to add %s to hash table\n",
5823
(const xmlChar *) tmpname, NULL);
5824
}
5825
}
5826
}
5827
}
5828
5829
/**
5830
* xmlRelaxNGCheckCycles:
5831
* @ctxt: a Relax-NG parser context
5832
* @nodes: grammar children nodes
5833
* @depth: the counter
5834
*
5835
* Check for cycles.
5836
*
5837
* Returns 0 if check passed, and -1 in case of error
5838
*/
5839
static int
5840
xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5841
xmlRelaxNGDefinePtr cur, int depth)
5842
{
5843
int ret = 0;
5844
5845
while ((ret == 0) && (cur != NULL)) {
5846
if ((cur->type == XML_RELAXNG_REF) ||
5847
(cur->type == XML_RELAXNG_PARENTREF)) {
5848
if (cur->depth == -1) {
5849
cur->depth = depth;
5850
ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5851
cur->depth = -2;
5852
} else if (depth == cur->depth) {
5853
xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
5854
"Detected a cycle in %s references\n",
5855
cur->name, NULL);
5856
return (-1);
5857
}
5858
} else if (cur->type == XML_RELAXNG_ELEMENT) {
5859
ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5860
} else {
5861
ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5862
}
5863
cur = cur->next;
5864
}
5865
return (ret);
5866
}
5867
5868
/**
5869
* xmlRelaxNGTryUnlink:
5870
* @ctxt: a Relax-NG parser context
5871
* @cur: the definition to unlink
5872
* @parent: the parent definition
5873
* @prev: the previous sibling definition
5874
*
5875
* Try to unlink a definition. If not possible make it a NOOP
5876
*
5877
* Returns the new prev definition
5878
*/
5879
static xmlRelaxNGDefinePtr
5880
xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5881
xmlRelaxNGDefinePtr cur,
5882
xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
5883
{
5884
if (prev != NULL) {
5885
prev->next = cur->next;
5886
} else {
5887
if (parent != NULL) {
5888
if (parent->content == cur)
5889
parent->content = cur->next;
5890
else if (parent->attrs == cur)
5891
parent->attrs = cur->next;
5892
else if (parent->nameClass == cur)
5893
parent->nameClass = cur->next;
5894
} else {
5895
cur->type = XML_RELAXNG_NOOP;
5896
prev = cur;
5897
}
5898
}
5899
return (prev);
5900
}
5901
5902
/**
5903
* xmlRelaxNGSimplify:
5904
* @ctxt: a Relax-NG parser context
5905
* @nodes: grammar children nodes
5906
*
5907
* Check for simplification of empty and notAllowed
5908
*/
5909
static void
5910
xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5911
xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
5912
{
5913
xmlRelaxNGDefinePtr prev = NULL;
5914
5915
while (cur != NULL) {
5916
if ((cur->type == XML_RELAXNG_REF) ||
5917
(cur->type == XML_RELAXNG_PARENTREF)) {
5918
if (cur->depth != -3) {
5919
cur->depth = -3;
5920
xmlRelaxNGSimplify(ctxt, cur->content, cur);
5921
}
5922
} else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5923
cur->parent = parent;
5924
if ((parent != NULL) &&
5925
((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5926
(parent->type == XML_RELAXNG_LIST) ||
5927
(parent->type == XML_RELAXNG_GROUP) ||
5928
(parent->type == XML_RELAXNG_INTERLEAVE) ||
5929
(parent->type == XML_RELAXNG_ONEORMORE) ||
5930
(parent->type == XML_RELAXNG_ZEROORMORE))) {
5931
parent->type = XML_RELAXNG_NOT_ALLOWED;
5932
break;
5933
}
5934
if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
5935
prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5936
} else
5937
prev = cur;
5938
} else if (cur->type == XML_RELAXNG_EMPTY) {
5939
cur->parent = parent;
5940
if ((parent != NULL) &&
5941
((parent->type == XML_RELAXNG_ONEORMORE) ||
5942
(parent->type == XML_RELAXNG_ZEROORMORE))) {
5943
parent->type = XML_RELAXNG_EMPTY;
5944
break;
5945
}
5946
if ((parent != NULL) &&
5947
((parent->type == XML_RELAXNG_GROUP) ||
5948
(parent->type == XML_RELAXNG_INTERLEAVE))) {
5949
prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5950
} else
5951
prev = cur;
5952
} else {
5953
cur->parent = parent;
5954
if (cur->content != NULL)
5955
xmlRelaxNGSimplify(ctxt, cur->content, cur);
5956
if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
5957
xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5958
if (cur->nameClass != NULL)
5959
xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5960
/*
5961
* On Elements, try to move attribute only generating rules on
5962
* the attrs rules.
5963
*/
5964
if (cur->type == XML_RELAXNG_ELEMENT) {
5965
int attronly;
5966
xmlRelaxNGDefinePtr tmp, pre;
5967
5968
while (cur->content != NULL) {
5969
attronly =
5970
xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5971
if (attronly == 1) {
5972
/*
5973
* migrate cur->content to attrs
5974
*/
5975
tmp = cur->content;
5976
cur->content = tmp->next;
5977
tmp->next = cur->attrs;
5978
cur->attrs = tmp;
5979
} else {
5980
/*
5981
* cur->content can generate elements or text
5982
*/
5983
break;
5984
}
5985
}
5986
pre = cur->content;
5987
while ((pre != NULL) && (pre->next != NULL)) {
5988
tmp = pre->next;
5989
attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5990
if (attronly == 1) {
5991
/*
5992
* migrate tmp to attrs
5993
*/
5994
pre->next = tmp->next;
5995
tmp->next = cur->attrs;
5996
cur->attrs = tmp;
5997
} else {
5998
pre = tmp;
5999
}
6000
}
6001
}
6002
/*
6003
* This may result in a simplification
6004
*/
6005
if ((cur->type == XML_RELAXNG_GROUP) ||
6006
(cur->type == XML_RELAXNG_INTERLEAVE)) {
6007
if (cur->content == NULL)
6008
cur->type = XML_RELAXNG_EMPTY;
6009
else if (cur->content->next == NULL) {
6010
if ((parent == NULL) && (prev == NULL)) {
6011
cur->type = XML_RELAXNG_NOOP;
6012
} else if (prev == NULL) {
6013
parent->content = cur->content;
6014
cur->content->next = cur->next;
6015
cur = cur->content;
6016
} else {
6017
cur->content->next = cur->next;
6018
prev->next = cur->content;
6019
cur = cur->content;
6020
}
6021
}
6022
}
6023
/*
6024
* the current node may have been transformed back
6025
*/
6026
if ((cur->type == XML_RELAXNG_EXCEPT) &&
6027
(cur->content != NULL) &&
6028
(cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
6029
prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6030
} else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
6031
if ((parent != NULL) &&
6032
((parent->type == XML_RELAXNG_ATTRIBUTE) ||
6033
(parent->type == XML_RELAXNG_LIST) ||
6034
(parent->type == XML_RELAXNG_GROUP) ||
6035
(parent->type == XML_RELAXNG_INTERLEAVE) ||
6036
(parent->type == XML_RELAXNG_ONEORMORE) ||
6037
(parent->type == XML_RELAXNG_ZEROORMORE))) {
6038
parent->type = XML_RELAXNG_NOT_ALLOWED;
6039
break;
6040
}
6041
if ((parent != NULL) &&
6042
(parent->type == XML_RELAXNG_CHOICE)) {
6043
prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6044
} else
6045
prev = cur;
6046
} else if (cur->type == XML_RELAXNG_EMPTY) {
6047
if ((parent != NULL) &&
6048
((parent->type == XML_RELAXNG_ONEORMORE) ||
6049
(parent->type == XML_RELAXNG_ZEROORMORE))) {
6050
parent->type = XML_RELAXNG_EMPTY;
6051
break;
6052
}
6053
if ((parent != NULL) &&
6054
((parent->type == XML_RELAXNG_GROUP) ||
6055
(parent->type == XML_RELAXNG_INTERLEAVE) ||
6056
(parent->type == XML_RELAXNG_CHOICE))) {
6057
prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
6058
} else
6059
prev = cur;
6060
} else {
6061
prev = cur;
6062
}
6063
}
6064
cur = cur->next;
6065
}
6066
}
6067
6068
/**
6069
* xmlRelaxNGGroupContentType:
6070
* @ct1: the first content type
6071
* @ct2: the second content type
6072
*
6073
* Try to group 2 content types
6074
*
6075
* Returns the content type
6076
*/
6077
static xmlRelaxNGContentType
6078
xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
6079
xmlRelaxNGContentType ct2)
6080
{
6081
if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6082
(ct2 == XML_RELAXNG_CONTENT_ERROR))
6083
return (XML_RELAXNG_CONTENT_ERROR);
6084
if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
6085
return (ct2);
6086
if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
6087
return (ct1);
6088
if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
6089
(ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6090
return (XML_RELAXNG_CONTENT_COMPLEX);
6091
return (XML_RELAXNG_CONTENT_ERROR);
6092
}
6093
6094
/**
6095
* xmlRelaxNGMaxContentType:
6096
* @ct1: the first content type
6097
* @ct2: the second content type
6098
*
6099
* Compute the max content-type
6100
*
6101
* Returns the content type
6102
*/
6103
static xmlRelaxNGContentType
6104
xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
6105
xmlRelaxNGContentType ct2)
6106
{
6107
if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
6108
(ct2 == XML_RELAXNG_CONTENT_ERROR))
6109
return (XML_RELAXNG_CONTENT_ERROR);
6110
if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
6111
(ct2 == XML_RELAXNG_CONTENT_SIMPLE))
6112
return (XML_RELAXNG_CONTENT_SIMPLE);
6113
if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
6114
(ct2 == XML_RELAXNG_CONTENT_COMPLEX))
6115
return (XML_RELAXNG_CONTENT_COMPLEX);
6116
return (XML_RELAXNG_CONTENT_EMPTY);
6117
}
6118
6119
/**
6120
* xmlRelaxNGCheckRules:
6121
* @ctxt: a Relax-NG parser context
6122
* @cur: the current definition
6123
* @flags: some accumulated flags
6124
* @ptype: the parent type
6125
*
6126
* Check for rules in section 7.1 and 7.2
6127
*
6128
* Returns the content type of @cur
6129
*/
6130
static xmlRelaxNGContentType
6131
xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
6132
xmlRelaxNGDefinePtr cur, int flags,
6133
xmlRelaxNGType ptype)
6134
{
6135
int nflags;
6136
xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
6137
6138
while (cur != NULL) {
6139
ret = XML_RELAXNG_CONTENT_EMPTY;
6140
if ((cur->type == XML_RELAXNG_REF) ||
6141
(cur->type == XML_RELAXNG_PARENTREF)) {
6142
/*
6143
* This should actually be caught by list//element(ref) at the
6144
* element boundaries, c.f. Bug #159968 local refs are dropped
6145
* in step 4.19.
6146
*/
6147
#if 0
6148
if (flags & XML_RELAXNG_IN_LIST) {
6149
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
6150
"Found forbidden pattern list//ref\n", NULL,
6151
NULL);
6152
}
6153
#endif
6154
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6155
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
6156
"Found forbidden pattern data/except//ref\n",
6157
NULL, NULL);
6158
}
6159
if (cur->content == NULL) {
6160
if (cur->type == XML_RELAXNG_PARENTREF)
6161
xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6162
"Internal found no define for parent refs\n",
6163
NULL, NULL);
6164
else
6165
xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
6166
"Internal found no define for ref %s\n",
6167
(cur->name ? cur->name: BAD_CAST "null"), NULL);
6168
}
6169
if (cur->depth > -4) {
6170
cur->depth = -4;
6171
ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6172
flags, cur->type);
6173
cur->depth = ret - 15;
6174
} else if (cur->depth == -4) {
6175
ret = XML_RELAXNG_CONTENT_COMPLEX;
6176
} else {
6177
ret = (xmlRelaxNGContentType) (cur->depth + 15);
6178
}
6179
} else if (cur->type == XML_RELAXNG_ELEMENT) {
6180
/*
6181
* The 7.3 Attribute derivation rule for groups is plugged there
6182
*/
6183
xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6184
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6185
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
6186
"Found forbidden pattern data/except//element(ref)\n",
6187
NULL, NULL);
6188
}
6189
if (flags & XML_RELAXNG_IN_LIST) {
6190
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
6191
"Found forbidden pattern list//element(ref)\n",
6192
NULL, NULL);
6193
}
6194
if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6195
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6196
"Found forbidden pattern attribute//element(ref)\n",
6197
NULL, NULL);
6198
}
6199
if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6200
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
6201
"Found forbidden pattern attribute//element(ref)\n",
6202
NULL, NULL);
6203
}
6204
/*
6205
* reset since in the simple form elements are only child
6206
* of grammar/define
6207
*/
6208
nflags = 0;
6209
ret =
6210
xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6211
if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6212
xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
6213
"Element %s attributes have a content type error\n",
6214
cur->name, NULL);
6215
}
6216
ret =
6217
xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6218
cur->type);
6219
if (ret == XML_RELAXNG_CONTENT_ERROR) {
6220
xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
6221
"Element %s has a content type error\n",
6222
cur->name, NULL);
6223
} else {
6224
ret = XML_RELAXNG_CONTENT_COMPLEX;
6225
}
6226
} else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6227
if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6228
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
6229
"Found forbidden pattern attribute//attribute\n",
6230
NULL, NULL);
6231
}
6232
if (flags & XML_RELAXNG_IN_LIST) {
6233
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
6234
"Found forbidden pattern list//attribute\n",
6235
NULL, NULL);
6236
}
6237
if (flags & XML_RELAXNG_IN_OOMGROUP) {
6238
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
6239
"Found forbidden pattern oneOrMore//group//attribute\n",
6240
NULL, NULL);
6241
}
6242
if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6243
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
6244
"Found forbidden pattern oneOrMore//interleave//attribute\n",
6245
NULL, NULL);
6246
}
6247
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6248
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
6249
"Found forbidden pattern data/except//attribute\n",
6250
NULL, NULL);
6251
}
6252
if (flags & XML_RELAXNG_IN_START) {
6253
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
6254
"Found forbidden pattern start//attribute\n",
6255
NULL, NULL);
6256
}
6257
if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
6258
&& cur->name == NULL
6259
/* following is checking alternative name class readiness
6260
in case it went the "choice" route */
6261
&& cur->nameClass == NULL) {
6262
if (cur->ns == NULL) {
6263
xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
6264
"Found anyName attribute without oneOrMore ancestor\n",
6265
NULL, NULL);
6266
} else {
6267
xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
6268
"Found nsName attribute without oneOrMore ancestor\n",
6269
NULL, NULL);
6270
}
6271
}
6272
nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6273
xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6274
ret = XML_RELAXNG_CONTENT_EMPTY;
6275
} else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6276
(cur->type == XML_RELAXNG_ZEROORMORE)) {
6277
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6278
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
6279
"Found forbidden pattern data/except//oneOrMore\n",
6280
NULL, NULL);
6281
}
6282
if (flags & XML_RELAXNG_IN_START) {
6283
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
6284
"Found forbidden pattern start//oneOrMore\n",
6285
NULL, NULL);
6286
}
6287
nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6288
ret =
6289
xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6290
cur->type);
6291
ret = xmlRelaxNGGroupContentType(ret, ret);
6292
} else if (cur->type == XML_RELAXNG_LIST) {
6293
if (flags & XML_RELAXNG_IN_LIST) {
6294
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
6295
"Found forbidden pattern list//list\n", NULL,
6296
NULL);
6297
}
6298
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6299
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
6300
"Found forbidden pattern data/except//list\n",
6301
NULL, NULL);
6302
}
6303
if (flags & XML_RELAXNG_IN_START) {
6304
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
6305
"Found forbidden pattern start//list\n", NULL,
6306
NULL);
6307
}
6308
nflags = flags | XML_RELAXNG_IN_LIST;
6309
ret =
6310
xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6311
cur->type);
6312
} else if (cur->type == XML_RELAXNG_GROUP) {
6313
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6314
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
6315
"Found forbidden pattern data/except//group\n",
6316
NULL, NULL);
6317
}
6318
if (flags & XML_RELAXNG_IN_START) {
6319
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
6320
"Found forbidden pattern start//group\n", NULL,
6321
NULL);
6322
}
6323
if (flags & XML_RELAXNG_IN_ONEORMORE)
6324
nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6325
else
6326
nflags = flags;
6327
ret =
6328
xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6329
cur->type);
6330
/*
6331
* The 7.3 Attribute derivation rule for groups is plugged there
6332
*/
6333
xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6334
} else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6335
if (flags & XML_RELAXNG_IN_LIST) {
6336
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
6337
"Found forbidden pattern list//interleave\n",
6338
NULL, NULL);
6339
}
6340
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6341
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6342
"Found forbidden pattern data/except//interleave\n",
6343
NULL, NULL);
6344
}
6345
if (flags & XML_RELAXNG_IN_START) {
6346
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
6347
"Found forbidden pattern start//interleave\n",
6348
NULL, NULL);
6349
}
6350
if (flags & XML_RELAXNG_IN_ONEORMORE)
6351
nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6352
else
6353
nflags = flags;
6354
ret =
6355
xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6356
cur->type);
6357
} else if (cur->type == XML_RELAXNG_EXCEPT) {
6358
if ((cur->parent != NULL) &&
6359
(cur->parent->type == XML_RELAXNG_DATATYPE))
6360
nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6361
else
6362
nflags = flags;
6363
ret =
6364
xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
6365
cur->type);
6366
} else if (cur->type == XML_RELAXNG_DATATYPE) {
6367
if (flags & XML_RELAXNG_IN_START) {
6368
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
6369
"Found forbidden pattern start//data\n", NULL,
6370
NULL);
6371
}
6372
xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6373
ret = XML_RELAXNG_CONTENT_SIMPLE;
6374
} else if (cur->type == XML_RELAXNG_VALUE) {
6375
if (flags & XML_RELAXNG_IN_START) {
6376
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
6377
"Found forbidden pattern start//value\n", NULL,
6378
NULL);
6379
}
6380
xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6381
ret = XML_RELAXNG_CONTENT_SIMPLE;
6382
} else if (cur->type == XML_RELAXNG_TEXT) {
6383
if (flags & XML_RELAXNG_IN_LIST) {
6384
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
6385
"Found forbidden pattern list//text\n", NULL,
6386
NULL);
6387
}
6388
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6389
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
6390
"Found forbidden pattern data/except//text\n",
6391
NULL, NULL);
6392
}
6393
if (flags & XML_RELAXNG_IN_START) {
6394
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
6395
"Found forbidden pattern start//text\n", NULL,
6396
NULL);
6397
}
6398
ret = XML_RELAXNG_CONTENT_COMPLEX;
6399
} else if (cur->type == XML_RELAXNG_EMPTY) {
6400
if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6401
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
6402
"Found forbidden pattern data/except//empty\n",
6403
NULL, NULL);
6404
}
6405
if (flags & XML_RELAXNG_IN_START) {
6406
xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
6407
"Found forbidden pattern start//empty\n", NULL,
6408
NULL);
6409
}
6410
ret = XML_RELAXNG_CONTENT_EMPTY;
6411
} else if (cur->type == XML_RELAXNG_CHOICE) {
6412
xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6413
ret =
6414
xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6415
} else {
6416
ret =
6417
xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6418
}
6419
cur = cur->next;
6420
if (ptype == XML_RELAXNG_GROUP) {
6421
val = xmlRelaxNGGroupContentType(val, ret);
6422
} else if (ptype == XML_RELAXNG_INTERLEAVE) {
6423
/*
6424
* TODO: scan complain that tmp is never used, seems on purpose
6425
* need double-checking
6426
*/
6427
tmp = xmlRelaxNGGroupContentType(val, ret);
6428
if (tmp != XML_RELAXNG_CONTENT_ERROR)
6429
tmp = xmlRelaxNGMaxContentType(val, ret);
6430
} else if (ptype == XML_RELAXNG_CHOICE) {
6431
val = xmlRelaxNGMaxContentType(val, ret);
6432
} else if (ptype == XML_RELAXNG_LIST) {
6433
val = XML_RELAXNG_CONTENT_SIMPLE;
6434
} else if (ptype == XML_RELAXNG_EXCEPT) {
6435
if (ret == XML_RELAXNG_CONTENT_ERROR)
6436
val = XML_RELAXNG_CONTENT_ERROR;
6437
else
6438
val = XML_RELAXNG_CONTENT_SIMPLE;
6439
} else {
6440
val = xmlRelaxNGGroupContentType(val, ret);
6441
}
6442
6443
}
6444
return (val);
6445
}
6446
6447
/**
6448
* xmlRelaxNGParseGrammar:
6449
* @ctxt: a Relax-NG parser context
6450
* @nodes: grammar children nodes
6451
*
6452
* parse a Relax-NG <grammar> node
6453
*
6454
* Returns the internal xmlRelaxNGGrammarPtr built or
6455
* NULL in case of error
6456
*/
6457
static xmlRelaxNGGrammarPtr
6458
xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
6459
{
6460
xmlRelaxNGGrammarPtr ret, tmp, old;
6461
6462
ret = xmlRelaxNGNewGrammar(ctxt);
6463
if (ret == NULL)
6464
return (NULL);
6465
6466
/*
6467
* Link the new grammar in the tree
6468
*/
6469
ret->parent = ctxt->grammar;
6470
if (ctxt->grammar != NULL) {
6471
tmp = ctxt->grammar->children;
6472
if (tmp == NULL) {
6473
ctxt->grammar->children = ret;
6474
} else {
6475
while (tmp->next != NULL)
6476
tmp = tmp->next;
6477
tmp->next = ret;
6478
}
6479
}
6480
6481
old = ctxt->grammar;
6482
ctxt->grammar = ret;
6483
xmlRelaxNGParseGrammarContent(ctxt, nodes);
6484
ctxt->grammar = ret;
6485
if (ctxt->grammar == NULL) {
6486
xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
6487
"Failed to parse <grammar> content\n", NULL, NULL);
6488
} else if (ctxt->grammar->start == NULL) {
6489
xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
6490
"Element <grammar> has no <start>\n", NULL, NULL);
6491
}
6492
6493
/*
6494
* Apply 4.17 merging rules to defines and starts
6495
*/
6496
xmlRelaxNGCombineStart(ctxt, ret);
6497
if (ret->defs != NULL) {
6498
xmlHashScan(ret->defs, xmlRelaxNGCheckCombine, ctxt);
6499
}
6500
6501
/*
6502
* link together defines and refs in this grammar
6503
*/
6504
if (ret->refs != NULL) {
6505
xmlHashScan(ret->refs, xmlRelaxNGCheckReference, ctxt);
6506
}
6507
6508
6509
/* @@@@ */
6510
6511
ctxt->grammar = old;
6512
return (ret);
6513
}
6514
6515
/**
6516
* xmlRelaxNGParseDocument:
6517
* @ctxt: a Relax-NG parser context
6518
* @node: the root node of the RelaxNG schema
6519
*
6520
* parse a Relax-NG definition resource and build an internal
6521
* xmlRelaxNG structure which can be used to validate instances.
6522
*
6523
* Returns the internal XML RelaxNG structure built or
6524
* NULL in case of error
6525
*/
6526
static xmlRelaxNGPtr
6527
xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6528
{
6529
xmlRelaxNGPtr schema = NULL;
6530
const xmlChar *olddefine;
6531
xmlRelaxNGGrammarPtr old;
6532
6533
if ((ctxt == NULL) || (node == NULL))
6534
return (NULL);
6535
6536
schema = xmlRelaxNGNewRelaxNG(ctxt);
6537
if (schema == NULL)
6538
return (NULL);
6539
6540
olddefine = ctxt->define;
6541
ctxt->define = NULL;
6542
if (IS_RELAXNG(node, "grammar")) {
6543
schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6544
if (schema->topgrammar == NULL) {
6545
xmlRelaxNGFree(schema);
6546
return (NULL);
6547
}
6548
} else {
6549
xmlRelaxNGGrammarPtr tmp, ret;
6550
6551
schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
6552
if (schema->topgrammar == NULL) {
6553
xmlRelaxNGFree(schema);
6554
return (NULL);
6555
}
6556
/*
6557
* Link the new grammar in the tree
6558
*/
6559
ret->parent = ctxt->grammar;
6560
if (ctxt->grammar != NULL) {
6561
tmp = ctxt->grammar->children;
6562
if (tmp == NULL) {
6563
ctxt->grammar->children = ret;
6564
} else {
6565
while (tmp->next != NULL)
6566
tmp = tmp->next;
6567
tmp->next = ret;
6568
}
6569
}
6570
old = ctxt->grammar;
6571
ctxt->grammar = ret;
6572
xmlRelaxNGParseStart(ctxt, node);
6573
if (old != NULL)
6574
ctxt->grammar = old;
6575
}
6576
ctxt->define = olddefine;
6577
if (schema->topgrammar->start != NULL) {
6578
xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
6579
if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
6580
xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6581
while ((schema->topgrammar->start != NULL) &&
6582
(schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6583
(schema->topgrammar->start->next != NULL))
6584
schema->topgrammar->start =
6585
schema->topgrammar->start->content;
6586
xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6587
XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
6588
}
6589
}
6590
6591
return (schema);
6592
}
6593
6594
/************************************************************************
6595
* *
6596
* Reading RelaxNGs *
6597
* *
6598
************************************************************************/
6599
6600
/**
6601
* xmlRelaxNGNewParserCtxt:
6602
* @URL: the location of the schema
6603
*
6604
* Create an XML RelaxNGs parse context for that file/resource expected
6605
* to contain an XML RelaxNGs file.
6606
*
6607
* Returns the parser context or NULL in case of error
6608
*/
6609
xmlRelaxNGParserCtxtPtr
6610
xmlRelaxNGNewParserCtxt(const char *URL)
6611
{
6612
xmlRelaxNGParserCtxtPtr ret;
6613
6614
if (URL == NULL)
6615
return (NULL);
6616
6617
ret =
6618
(xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6619
if (ret == NULL) {
6620
xmlRngPErrMemory(NULL, "building parser\n");
6621
return (NULL);
6622
}
6623
memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6624
ret->URL = xmlStrdup((const xmlChar *) URL);
6625
ret->error = xmlGenericError;
6626
ret->userData = xmlGenericErrorContext;
6627
return (ret);
6628
}
6629
6630
/**
6631
* xmlRelaxNGNewMemParserCtxt:
6632
* @buffer: a pointer to a char array containing the schemas
6633
* @size: the size of the array
6634
*
6635
* Create an XML RelaxNGs parse context for that memory buffer expected
6636
* to contain an XML RelaxNGs file.
6637
*
6638
* Returns the parser context or NULL in case of error
6639
*/
6640
xmlRelaxNGParserCtxtPtr
6641
xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
6642
{
6643
xmlRelaxNGParserCtxtPtr ret;
6644
6645
if ((buffer == NULL) || (size <= 0))
6646
return (NULL);
6647
6648
ret =
6649
(xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6650
if (ret == NULL) {
6651
xmlRngPErrMemory(NULL, "building parser\n");
6652
return (NULL);
6653
}
6654
memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6655
ret->buffer = buffer;
6656
ret->size = size;
6657
ret->error = xmlGenericError;
6658
ret->userData = xmlGenericErrorContext;
6659
return (ret);
6660
}
6661
6662
/**
6663
* xmlRelaxNGNewDocParserCtxt:
6664
* @doc: a preparsed document tree
6665
*
6666
* Create an XML RelaxNGs parser context for that document.
6667
* Note: since the process of compiling a RelaxNG schemas modifies the
6668
* document, the @doc parameter is duplicated internally.
6669
*
6670
* Returns the parser context or NULL in case of error
6671
*/
6672
xmlRelaxNGParserCtxtPtr
6673
xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
6674
{
6675
xmlRelaxNGParserCtxtPtr ret;
6676
xmlDocPtr copy;
6677
6678
if (doc == NULL)
6679
return (NULL);
6680
copy = xmlCopyDoc(doc, 1);
6681
if (copy == NULL)
6682
return (NULL);
6683
6684
ret =
6685
(xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6686
if (ret == NULL) {
6687
xmlRngPErrMemory(NULL, "building parser\n");
6688
xmlFreeDoc(copy);
6689
return (NULL);
6690
}
6691
memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6692
ret->document = copy;
6693
ret->freedoc = 1;
6694
ret->userData = xmlGenericErrorContext;
6695
return (ret);
6696
}
6697
6698
/**
6699
* xmlRelaxNGFreeParserCtxt:
6700
* @ctxt: the schema parser context
6701
*
6702
* Free the resources associated to the schema parser context
6703
*/
6704
void
6705
xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
6706
{
6707
if (ctxt == NULL)
6708
return;
6709
if (ctxt->URL != NULL)
6710
xmlFree(ctxt->URL);
6711
if (ctxt->doc != NULL)
6712
xmlRelaxNGFreeDocument(ctxt->doc);
6713
if (ctxt->interleaves != NULL)
6714
xmlHashFree(ctxt->interleaves, NULL);
6715
if (ctxt->documents != NULL)
6716
xmlRelaxNGFreeDocumentList(ctxt->documents);
6717
if (ctxt->includes != NULL)
6718
xmlRelaxNGFreeIncludeList(ctxt->includes);
6719
if (ctxt->docTab != NULL)
6720
xmlFree(ctxt->docTab);
6721
if (ctxt->incTab != NULL)
6722
xmlFree(ctxt->incTab);
6723
if (ctxt->defTab != NULL) {
6724
int i;
6725
6726
for (i = 0; i < ctxt->defNr; i++)
6727
xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6728
xmlFree(ctxt->defTab);
6729
}
6730
if ((ctxt->document != NULL) && (ctxt->freedoc))
6731
xmlFreeDoc(ctxt->document);
6732
xmlFree(ctxt);
6733
}
6734
6735
/**
6736
* xmlRelaxNGNormExtSpace:
6737
* @value: a value
6738
*
6739
* Removes the leading and ending spaces of the value
6740
* The string is modified "in situ"
6741
*/
6742
static void
6743
xmlRelaxNGNormExtSpace(xmlChar * value)
6744
{
6745
xmlChar *start = value;
6746
xmlChar *cur = value;
6747
6748
if (value == NULL)
6749
return;
6750
6751
while (IS_BLANK_CH(*cur))
6752
cur++;
6753
if (cur == start) {
6754
do {
6755
while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6756
cur++;
6757
if (*cur == 0)
6758
return;
6759
start = cur;
6760
while (IS_BLANK_CH(*cur))
6761
cur++;
6762
if (*cur == 0) {
6763
*start = 0;
6764
return;
6765
}
6766
} while (1);
6767
} else {
6768
do {
6769
while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
6770
*start++ = *cur++;
6771
if (*cur == 0) {
6772
*start = 0;
6773
return;
6774
}
6775
/* don't try to normalize the inner spaces */
6776
while (IS_BLANK_CH(*cur))
6777
cur++;
6778
if (*cur == 0) {
6779
*start = 0;
6780
return;
6781
}
6782
*start++ = *cur++;
6783
} while (1);
6784
}
6785
}
6786
6787
/**
6788
* xmlRelaxNGCleanupAttributes:
6789
* @ctxt: a Relax-NG parser context
6790
* @node: a Relax-NG node
6791
*
6792
* Check all the attributes on the given node
6793
*/
6794
static void
6795
xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
6796
{
6797
xmlAttrPtr cur, next;
6798
6799
cur = node->properties;
6800
while (cur != NULL) {
6801
next = cur->next;
6802
if ((cur->ns == NULL) ||
6803
(xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6804
if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6805
if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6806
(!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6807
(!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6808
(!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
6809
(!xmlStrEqual(node->name, BAD_CAST "param")) &&
6810
(!xmlStrEqual(node->name, BAD_CAST "define"))) {
6811
xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6812
"Attribute %s is not allowed on %s\n",
6813
cur->name, node->name);
6814
}
6815
} else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6816
if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6817
(!xmlStrEqual(node->name, BAD_CAST "data"))) {
6818
xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6819
"Attribute %s is not allowed on %s\n",
6820
cur->name, node->name);
6821
}
6822
} else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6823
if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6824
(!xmlStrEqual(node->name, BAD_CAST "include"))) {
6825
xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6826
"Attribute %s is not allowed on %s\n",
6827
cur->name, node->name);
6828
}
6829
} else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6830
if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6831
(!xmlStrEqual(node->name, BAD_CAST "define"))) {
6832
xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
6833
"Attribute %s is not allowed on %s\n",
6834
cur->name, node->name);
6835
}
6836
} else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6837
xmlChar *val;
6838
xmlURIPtr uri;
6839
6840
val = xmlNodeListGetString(node->doc, cur->children, 1);
6841
if (val != NULL) {
6842
if (val[0] != 0) {
6843
uri = xmlParseURI((const char *) val);
6844
if (uri == NULL) {
6845
xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
6846
"Attribute %s contains invalid URI %s\n",
6847
cur->name, val);
6848
} else {
6849
if (uri->scheme == NULL) {
6850
xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
6851
"Attribute %s URI %s is not absolute\n",
6852
cur->name, val);
6853
}
6854
if (uri->fragment != NULL) {
6855
xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
6856
"Attribute %s URI %s has a fragment ID\n",
6857
cur->name, val);
6858
}
6859
xmlFreeURI(uri);
6860
}
6861
}
6862
xmlFree(val);
6863
}
6864
} else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6865
xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
6866
"Unknown attribute %s on %s\n", cur->name,
6867
node->name);
6868
}
6869
}
6870
cur = next;
6871
}
6872
}
6873
6874
/**
6875
* xmlRelaxNGCleanupTree:
6876
* @ctxt: a Relax-NG parser context
6877
* @root: an xmlNodePtr subtree
6878
*
6879
* Cleanup the subtree from unwanted nodes for parsing, resolve
6880
* Include and externalRef lookups.
6881
*/
6882
static void
6883
xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
6884
{
6885
xmlNodePtr cur, delete;
6886
6887
delete = NULL;
6888
cur = root;
6889
while (cur != NULL) {
6890
if (delete != NULL) {
6891
xmlUnlinkNode(delete);
6892
xmlFreeNode(delete);
6893
delete = NULL;
6894
}
6895
if (cur->type == XML_ELEMENT_NODE) {
6896
/*
6897
* Simplification 4.1. Annotations
6898
*/
6899
if ((cur->ns == NULL) ||
6900
(!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6901
if ((cur->parent != NULL) &&
6902
(cur->parent->type == XML_ELEMENT_NODE) &&
6903
((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6904
(xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6905
(xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6906
xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
6907
"element %s doesn't allow foreign elements\n",
6908
cur->parent->name, NULL);
6909
}
6910
delete = cur;
6911
goto skip_children;
6912
} else {
6913
xmlRelaxNGCleanupAttributes(ctxt, cur);
6914
if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6915
xmlChar *href, *ns, *base, *URL;
6916
xmlRelaxNGDocumentPtr docu;
6917
xmlNodePtr tmp;
6918
xmlURIPtr uri;
6919
6920
ns = xmlGetProp(cur, BAD_CAST "ns");
6921
if (ns == NULL) {
6922
tmp = cur->parent;
6923
while ((tmp != NULL) &&
6924
(tmp->type == XML_ELEMENT_NODE)) {
6925
ns = xmlGetProp(tmp, BAD_CAST "ns");
6926
if (ns != NULL)
6927
break;
6928
tmp = tmp->parent;
6929
}
6930
}
6931
href = xmlGetProp(cur, BAD_CAST "href");
6932
if (href == NULL) {
6933
xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
6934
"xmlRelaxNGParse: externalRef has no href attribute\n",
6935
NULL, NULL);
6936
if (ns != NULL)
6937
xmlFree(ns);
6938
delete = cur;
6939
goto skip_children;
6940
}
6941
uri = xmlParseURI((const char *) href);
6942
if (uri == NULL) {
6943
xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6944
"Incorrect URI for externalRef %s\n",
6945
href, NULL);
6946
if (ns != NULL)
6947
xmlFree(ns);
6948
if (href != NULL)
6949
xmlFree(href);
6950
delete = cur;
6951
goto skip_children;
6952
}
6953
if (uri->fragment != NULL) {
6954
xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6955
"Fragment forbidden in URI for externalRef %s\n",
6956
href, NULL);
6957
if (ns != NULL)
6958
xmlFree(ns);
6959
xmlFreeURI(uri);
6960
if (href != NULL)
6961
xmlFree(href);
6962
delete = cur;
6963
goto skip_children;
6964
}
6965
xmlFreeURI(uri);
6966
base = xmlNodeGetBase(cur->doc, cur);
6967
URL = xmlBuildURI(href, base);
6968
if (URL == NULL) {
6969
xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
6970
"Failed to compute URL for externalRef %s\n",
6971
href, NULL);
6972
if (ns != NULL)
6973
xmlFree(ns);
6974
if (href != NULL)
6975
xmlFree(href);
6976
if (base != NULL)
6977
xmlFree(base);
6978
delete = cur;
6979
goto skip_children;
6980
}
6981
if (href != NULL)
6982
xmlFree(href);
6983
if (base != NULL)
6984
xmlFree(base);
6985
docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6986
if (docu == NULL) {
6987
xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
6988
"Failed to load externalRef %s\n", URL,
6989
NULL);
6990
if (ns != NULL)
6991
xmlFree(ns);
6992
xmlFree(URL);
6993
delete = cur;
6994
goto skip_children;
6995
}
6996
if (ns != NULL)
6997
xmlFree(ns);
6998
xmlFree(URL);
6999
cur->psvi = docu;
7000
} else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
7001
xmlChar *href, *ns, *base, *URL;
7002
xmlRelaxNGIncludePtr incl;
7003
xmlNodePtr tmp;
7004
7005
href = xmlGetProp(cur, BAD_CAST "href");
7006
if (href == NULL) {
7007
xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
7008
"xmlRelaxNGParse: include has no href attribute\n",
7009
NULL, NULL);
7010
delete = cur;
7011
goto skip_children;
7012
}
7013
base = xmlNodeGetBase(cur->doc, cur);
7014
URL = xmlBuildURI(href, base);
7015
if (URL == NULL) {
7016
xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
7017
"Failed to compute URL for include %s\n",
7018
href, NULL);
7019
if (href != NULL)
7020
xmlFree(href);
7021
if (base != NULL)
7022
xmlFree(base);
7023
delete = cur;
7024
goto skip_children;
7025
}
7026
if (href != NULL)
7027
xmlFree(href);
7028
if (base != NULL)
7029
xmlFree(base);
7030
ns = xmlGetProp(cur, BAD_CAST "ns");
7031
if (ns == NULL) {
7032
tmp = cur->parent;
7033
while ((tmp != NULL) &&
7034
(tmp->type == XML_ELEMENT_NODE)) {
7035
ns = xmlGetProp(tmp, BAD_CAST "ns");
7036
if (ns != NULL)
7037
break;
7038
tmp = tmp->parent;
7039
}
7040
}
7041
incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
7042
if (ns != NULL)
7043
xmlFree(ns);
7044
if (incl == NULL) {
7045
xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
7046
"Failed to load include %s\n", URL,
7047
NULL);
7048
xmlFree(URL);
7049
delete = cur;
7050
goto skip_children;
7051
}
7052
xmlFree(URL);
7053
cur->psvi = incl;
7054
} else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
7055
(xmlStrEqual(cur->name, BAD_CAST "attribute")))
7056
{
7057
xmlChar *name, *ns;
7058
xmlNodePtr text = NULL;
7059
7060
/*
7061
* Simplification 4.8. name attribute of element
7062
* and attribute elements
7063
*/
7064
name = xmlGetProp(cur, BAD_CAST "name");
7065
if (name != NULL) {
7066
if (cur->children == NULL) {
7067
text =
7068
xmlNewChild(cur, cur->ns, BAD_CAST "name",
7069
name);
7070
} else {
7071
xmlNodePtr node;
7072
7073
node = xmlNewDocNode(cur->doc, cur->ns,
7074
BAD_CAST "name", NULL);
7075
if (node != NULL) {
7076
xmlAddPrevSibling(cur->children, node);
7077
text = xmlNewDocText(node->doc, name);
7078
xmlAddChild(node, text);
7079
text = node;
7080
}
7081
}
7082
if (text == NULL) {
7083
xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
7084
"Failed to create a name %s element\n",
7085
name, NULL);
7086
}
7087
xmlUnsetProp(cur, BAD_CAST "name");
7088
xmlFree(name);
7089
ns = xmlGetProp(cur, BAD_CAST "ns");
7090
if (ns != NULL) {
7091
if (text != NULL) {
7092
xmlSetProp(text, BAD_CAST "ns", ns);
7093
/* xmlUnsetProp(cur, BAD_CAST "ns"); */
7094
}
7095
xmlFree(ns);
7096
} else if (xmlStrEqual(cur->name,
7097
BAD_CAST "attribute")) {
7098
xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
7099
}
7100
}
7101
} else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
7102
(xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
7103
(xmlStrEqual(cur->name, BAD_CAST "value"))) {
7104
/*
7105
* Simplification 4.8. name attribute of element
7106
* and attribute elements
7107
*/
7108
if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
7109
xmlNodePtr node;
7110
xmlChar *ns = NULL;
7111
7112
node = cur->parent;
7113
while ((node != NULL) &&
7114
(node->type == XML_ELEMENT_NODE)) {
7115
ns = xmlGetProp(node, BAD_CAST "ns");
7116
if (ns != NULL) {
7117
break;
7118
}
7119
node = node->parent;
7120
}
7121
if (ns == NULL) {
7122
xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
7123
} else {
7124
xmlSetProp(cur, BAD_CAST "ns", ns);
7125
xmlFree(ns);
7126
}
7127
}
7128
if (xmlStrEqual(cur->name, BAD_CAST "name")) {
7129
xmlChar *name, *local, *prefix;
7130
7131
/*
7132
* Simplification: 4.10. QNames
7133
*/
7134
name = xmlNodeGetContent(cur);
7135
if (name != NULL) {
7136
local = xmlSplitQName2(name, &prefix);
7137
if (local != NULL) {
7138
xmlNsPtr ns;
7139
7140
ns = xmlSearchNs(cur->doc, cur, prefix);
7141
if (ns == NULL) {
7142
xmlRngPErr(ctxt, cur,
7143
XML_RNGP_PREFIX_UNDEFINED,
7144
"xmlRelaxNGParse: no namespace for prefix %s\n",
7145
prefix, NULL);
7146
} else {
7147
xmlSetProp(cur, BAD_CAST "ns",
7148
ns->href);
7149
xmlNodeSetContent(cur, local);
7150
}
7151
xmlFree(local);
7152
xmlFree(prefix);
7153
}
7154
xmlFree(name);
7155
}
7156
}
7157
/*
7158
* 4.16
7159
*/
7160
if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
7161
if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7162
xmlRngPErr(ctxt, cur,
7163
XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
7164
"Found nsName/except//nsName forbidden construct\n",
7165
NULL, NULL);
7166
}
7167
}
7168
} else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
7169
(cur != root)) {
7170
int oldflags = ctxt->flags;
7171
7172
/*
7173
* 4.16
7174
*/
7175
if ((cur->parent != NULL) &&
7176
(xmlStrEqual
7177
(cur->parent->name, BAD_CAST "anyName"))) {
7178
ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
7179
xmlRelaxNGCleanupTree(ctxt, cur);
7180
ctxt->flags = oldflags;
7181
goto skip_children;
7182
} else if ((cur->parent != NULL) &&
7183
(xmlStrEqual
7184
(cur->parent->name, BAD_CAST "nsName"))) {
7185
ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7186
xmlRelaxNGCleanupTree(ctxt, cur);
7187
ctxt->flags = oldflags;
7188
goto skip_children;
7189
}
7190
} else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7191
/*
7192
* 4.16
7193
*/
7194
if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7195
xmlRngPErr(ctxt, cur,
7196
XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
7197
"Found anyName/except//anyName forbidden construct\n",
7198
NULL, NULL);
7199
} else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7200
xmlRngPErr(ctxt, cur,
7201
XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
7202
"Found nsName/except//anyName forbidden construct\n",
7203
NULL, NULL);
7204
}
7205
}
7206
/*
7207
* This is not an else since "include" is transformed
7208
* into a div
7209
*/
7210
if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7211
xmlChar *ns;
7212
xmlNodePtr child, ins, tmp;
7213
7214
/*
7215
* implements rule 4.11
7216
*/
7217
7218
ns = xmlGetProp(cur, BAD_CAST "ns");
7219
7220
child = cur->children;
7221
ins = cur;
7222
while (child != NULL) {
7223
if (ns != NULL) {
7224
if (!xmlHasProp(child, BAD_CAST "ns")) {
7225
xmlSetProp(child, BAD_CAST "ns", ns);
7226
}
7227
}
7228
tmp = child->next;
7229
xmlUnlinkNode(child);
7230
ins = xmlAddNextSibling(ins, child);
7231
child = tmp;
7232
}
7233
if (ns != NULL)
7234
xmlFree(ns);
7235
/*
7236
* Since we are about to delete cur, if its nsDef is non-NULL we
7237
* need to preserve it (it contains the ns definitions for the
7238
* children we just moved). We'll just stick it on to the end
7239
* of cur->parent's list, since it's never going to be re-serialized
7240
* (bug 143738).
7241
*/
7242
if ((cur->nsDef != NULL) && (cur->parent != NULL)) {
7243
xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
7244
while (parDef->next != NULL)
7245
parDef = parDef->next;
7246
parDef->next = cur->nsDef;
7247
cur->nsDef = NULL;
7248
}
7249
delete = cur;
7250
goto skip_children;
7251
}
7252
}
7253
}
7254
/*
7255
* Simplification 4.2 whitespaces
7256
*/
7257
else if ((cur->type == XML_TEXT_NODE) ||
7258
(cur->type == XML_CDATA_SECTION_NODE)) {
7259
if (IS_BLANK_NODE(cur)) {
7260
if ((cur->parent != NULL) &&
7261
(cur->parent->type == XML_ELEMENT_NODE)) {
7262
if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
7263
&&
7264
(!xmlStrEqual
7265
(cur->parent->name, BAD_CAST "param")))
7266
delete = cur;
7267
} else {
7268
delete = cur;
7269
goto skip_children;
7270
}
7271
}
7272
} else {
7273
delete = cur;
7274
goto skip_children;
7275
}
7276
7277
/*
7278
* Skip to next node
7279
*/
7280
if (cur->children != NULL) {
7281
if ((cur->children->type != XML_ENTITY_DECL) &&
7282
(cur->children->type != XML_ENTITY_REF_NODE) &&
7283
(cur->children->type != XML_ENTITY_NODE)) {
7284
cur = cur->children;
7285
continue;
7286
}
7287
}
7288
skip_children:
7289
if (cur->next != NULL) {
7290
cur = cur->next;
7291
continue;
7292
}
7293
7294
do {
7295
cur = cur->parent;
7296
if (cur == NULL)
7297
break;
7298
if (cur == root) {
7299
cur = NULL;
7300
break;
7301
}
7302
if (cur->next != NULL) {
7303
cur = cur->next;
7304
break;
7305
}
7306
} while (cur != NULL);
7307
}
7308
if (delete != NULL) {
7309
xmlUnlinkNode(delete);
7310
xmlFreeNode(delete);
7311
delete = NULL;
7312
}
7313
}
7314
7315
/**
7316
* xmlRelaxNGCleanupDoc:
7317
* @ctxt: a Relax-NG parser context
7318
* @doc: an xmldocPtr document pointer
7319
*
7320
* Cleanup the document from unwanted nodes for parsing, resolve
7321
* Include and externalRef lookups.
7322
*
7323
* Returns the cleaned up document or NULL in case of error
7324
*/
7325
static xmlDocPtr
7326
xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
7327
{
7328
xmlNodePtr root;
7329
7330
/*
7331
* Extract the root
7332
*/
7333
root = xmlDocGetRootElement(doc);
7334
if (root == NULL) {
7335
xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7336
ctxt->URL, NULL);
7337
return (NULL);
7338
}
7339
xmlRelaxNGCleanupTree(ctxt, root);
7340
return (doc);
7341
}
7342
7343
/**
7344
* xmlRelaxNGParse:
7345
* @ctxt: a Relax-NG parser context
7346
*
7347
* parse a schema definition resource and build an internal
7348
* XML Schema structure which can be used to validate instances.
7349
*
7350
* Returns the internal XML RelaxNG structure built from the resource or
7351
* NULL in case of error
7352
*/
7353
xmlRelaxNGPtr
7354
xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7355
{
7356
xmlRelaxNGPtr ret = NULL;
7357
xmlDocPtr doc;
7358
xmlNodePtr root;
7359
7360
xmlRelaxNGInitTypes();
7361
7362
if (ctxt == NULL)
7363
return (NULL);
7364
7365
/*
7366
* First step is to parse the input document into an DOM/Infoset
7367
*/
7368
if (ctxt->URL != NULL) {
7369
doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
7370
if (doc == NULL) {
7371
xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7372
"xmlRelaxNGParse: could not load %s\n", ctxt->URL,
7373
NULL);
7374
return (NULL);
7375
}
7376
} else if (ctxt->buffer != NULL) {
7377
doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
7378
if (doc == NULL) {
7379
xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
7380
"xmlRelaxNGParse: could not parse schemas\n", NULL,
7381
NULL);
7382
return (NULL);
7383
}
7384
doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7385
ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7386
} else if (ctxt->document != NULL) {
7387
doc = ctxt->document;
7388
} else {
7389
xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
7390
"xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
7391
return (NULL);
7392
}
7393
ctxt->document = doc;
7394
7395
/*
7396
* Some preprocessing of the document content
7397
*/
7398
doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7399
if (doc == NULL) {
7400
xmlFreeDoc(ctxt->document);
7401
ctxt->document = NULL;
7402
return (NULL);
7403
}
7404
7405
/*
7406
* Then do the parsing for good
7407
*/
7408
root = xmlDocGetRootElement(doc);
7409
if (root == NULL) {
7410
xmlRngPErr(ctxt, (xmlNodePtr) doc,
7411
XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
7412
(ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
7413
7414
xmlFreeDoc(ctxt->document);
7415
ctxt->document = NULL;
7416
return (NULL);
7417
}
7418
ret = xmlRelaxNGParseDocument(ctxt, root);
7419
if (ret == NULL) {
7420
xmlFreeDoc(ctxt->document);
7421
ctxt->document = NULL;
7422
return (NULL);
7423
}
7424
7425
/*
7426
* Check the ref/defines links
7427
*/
7428
/*
7429
* try to preprocess interleaves
7430
*/
7431
if (ctxt->interleaves != NULL) {
7432
xmlHashScan(ctxt->interleaves, xmlRelaxNGComputeInterleaves, ctxt);
7433
}
7434
7435
/*
7436
* if there was a parsing error return NULL
7437
*/
7438
if (ctxt->nbErrors > 0) {
7439
xmlRelaxNGFree(ret);
7440
ctxt->document = NULL;
7441
xmlFreeDoc(doc);
7442
return (NULL);
7443
}
7444
7445
/*
7446
* try to compile (parts of) the schemas
7447
*/
7448
if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7449
if (ret->topgrammar->start->type != XML_RELAXNG_START) {
7450
xmlRelaxNGDefinePtr def;
7451
7452
def = xmlRelaxNGNewDefine(ctxt, NULL);
7453
if (def != NULL) {
7454
def->type = XML_RELAXNG_START;
7455
def->content = ret->topgrammar->start;
7456
ret->topgrammar->start = def;
7457
}
7458
}
7459
xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
7460
}
7461
7462
/*
7463
* Transfer the pointer for cleanup at the schema level.
7464
*/
7465
ret->doc = doc;
7466
ctxt->document = NULL;
7467
ret->documents = ctxt->documents;
7468
ctxt->documents = NULL;
7469
7470
ret->includes = ctxt->includes;
7471
ctxt->includes = NULL;
7472
ret->defNr = ctxt->defNr;
7473
ret->defTab = ctxt->defTab;
7474
ctxt->defTab = NULL;
7475
if (ctxt->idref == 1)
7476
ret->idref = 1;
7477
7478
return (ret);
7479
}
7480
7481
/**
7482
* xmlRelaxNGSetParserErrors:
7483
* @ctxt: a Relax-NG validation context
7484
* @err: the error callback
7485
* @warn: the warning callback
7486
* @ctx: contextual data for the callbacks
7487
*
7488
* Set the callback functions used to handle errors for a validation context
7489
*/
7490
void
7491
xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7492
xmlRelaxNGValidityErrorFunc err,
7493
xmlRelaxNGValidityWarningFunc warn, void *ctx)
7494
{
7495
if (ctxt == NULL)
7496
return;
7497
ctxt->error = err;
7498
ctxt->warning = warn;
7499
ctxt->serror = NULL;
7500
ctxt->userData = ctx;
7501
}
7502
7503
/**
7504
* xmlRelaxNGGetParserErrors:
7505
* @ctxt: a Relax-NG validation context
7506
* @err: the error callback result
7507
* @warn: the warning callback result
7508
* @ctx: contextual data for the callbacks result
7509
*
7510
* Get the callback information used to handle errors for a validation context
7511
*
7512
* Returns -1 in case of failure, 0 otherwise.
7513
*/
7514
int
7515
xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7516
xmlRelaxNGValidityErrorFunc * err,
7517
xmlRelaxNGValidityWarningFunc * warn, void **ctx)
7518
{
7519
if (ctxt == NULL)
7520
return (-1);
7521
if (err != NULL)
7522
*err = ctxt->error;
7523
if (warn != NULL)
7524
*warn = ctxt->warning;
7525
if (ctx != NULL)
7526
*ctx = ctxt->userData;
7527
return (0);
7528
}
7529
7530
/**
7531
* xmlRelaxNGSetParserStructuredErrors:
7532
* @ctxt: a Relax-NG parser context
7533
* @serror: the error callback
7534
* @ctx: contextual data for the callbacks
7535
*
7536
* Set the callback functions used to handle errors for a parsing context
7537
*/
7538
void
7539
xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,
7540
xmlStructuredErrorFunc serror,
7541
void *ctx)
7542
{
7543
if (ctxt == NULL)
7544
return;
7545
ctxt->serror = serror;
7546
ctxt->error = NULL;
7547
ctxt->warning = NULL;
7548
ctxt->userData = ctx;
7549
}
7550
7551
#ifdef LIBXML_OUTPUT_ENABLED
7552
7553
/************************************************************************
7554
* *
7555
* Dump back a compiled form *
7556
* *
7557
************************************************************************/
7558
static void xmlRelaxNGDumpDefine(FILE * output,
7559
xmlRelaxNGDefinePtr define);
7560
7561
/**
7562
* xmlRelaxNGDumpDefines:
7563
* @output: the file output
7564
* @defines: a list of define structures
7565
*
7566
* Dump a RelaxNG structure back
7567
*/
7568
static void
7569
xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
7570
{
7571
while (defines != NULL) {
7572
xmlRelaxNGDumpDefine(output, defines);
7573
defines = defines->next;
7574
}
7575
}
7576
7577
/**
7578
* xmlRelaxNGDumpDefine:
7579
* @output: the file output
7580
* @define: a define structure
7581
*
7582
* Dump a RelaxNG structure back
7583
*/
7584
static void
7585
xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
7586
{
7587
if (define == NULL)
7588
return;
7589
switch (define->type) {
7590
case XML_RELAXNG_EMPTY:
7591
fprintf(output, "<empty/>\n");
7592
break;
7593
case XML_RELAXNG_NOT_ALLOWED:
7594
fprintf(output, "<notAllowed/>\n");
7595
break;
7596
case XML_RELAXNG_TEXT:
7597
fprintf(output, "<text/>\n");
7598
break;
7599
case XML_RELAXNG_ELEMENT:
7600
fprintf(output, "<element>\n");
7601
if (define->name != NULL) {
7602
fprintf(output, "<name");
7603
if (define->ns != NULL)
7604
fprintf(output, " ns=\"%s\"", define->ns);
7605
fprintf(output, ">%s</name>\n", define->name);
7606
}
7607
xmlRelaxNGDumpDefines(output, define->attrs);
7608
xmlRelaxNGDumpDefines(output, define->content);
7609
fprintf(output, "</element>\n");
7610
break;
7611
case XML_RELAXNG_LIST:
7612
fprintf(output, "<list>\n");
7613
xmlRelaxNGDumpDefines(output, define->content);
7614
fprintf(output, "</list>\n");
7615
break;
7616
case XML_RELAXNG_ONEORMORE:
7617
fprintf(output, "<oneOrMore>\n");
7618
xmlRelaxNGDumpDefines(output, define->content);
7619
fprintf(output, "</oneOrMore>\n");
7620
break;
7621
case XML_RELAXNG_ZEROORMORE:
7622
fprintf(output, "<zeroOrMore>\n");
7623
xmlRelaxNGDumpDefines(output, define->content);
7624
fprintf(output, "</zeroOrMore>\n");
7625
break;
7626
case XML_RELAXNG_CHOICE:
7627
fprintf(output, "<choice>\n");
7628
xmlRelaxNGDumpDefines(output, define->content);
7629
fprintf(output, "</choice>\n");
7630
break;
7631
case XML_RELAXNG_GROUP:
7632
fprintf(output, "<group>\n");
7633
xmlRelaxNGDumpDefines(output, define->content);
7634
fprintf(output, "</group>\n");
7635
break;
7636
case XML_RELAXNG_INTERLEAVE:
7637
fprintf(output, "<interleave>\n");
7638
xmlRelaxNGDumpDefines(output, define->content);
7639
fprintf(output, "</interleave>\n");
7640
break;
7641
case XML_RELAXNG_OPTIONAL:
7642
fprintf(output, "<optional>\n");
7643
xmlRelaxNGDumpDefines(output, define->content);
7644
fprintf(output, "</optional>\n");
7645
break;
7646
case XML_RELAXNG_ATTRIBUTE:
7647
fprintf(output, "<attribute>\n");
7648
xmlRelaxNGDumpDefines(output, define->content);
7649
fprintf(output, "</attribute>\n");
7650
break;
7651
case XML_RELAXNG_DEF:
7652
fprintf(output, "<define");
7653
if (define->name != NULL)
7654
fprintf(output, " name=\"%s\"", define->name);
7655
fprintf(output, ">\n");
7656
xmlRelaxNGDumpDefines(output, define->content);
7657
fprintf(output, "</define>\n");
7658
break;
7659
case XML_RELAXNG_REF:
7660
fprintf(output, "<ref");
7661
if (define->name != NULL)
7662
fprintf(output, " name=\"%s\"", define->name);
7663
fprintf(output, ">\n");
7664
xmlRelaxNGDumpDefines(output, define->content);
7665
fprintf(output, "</ref>\n");
7666
break;
7667
case XML_RELAXNG_PARENTREF:
7668
fprintf(output, "<parentRef");
7669
if (define->name != NULL)
7670
fprintf(output, " name=\"%s\"", define->name);
7671
fprintf(output, ">\n");
7672
xmlRelaxNGDumpDefines(output, define->content);
7673
fprintf(output, "</parentRef>\n");
7674
break;
7675
case XML_RELAXNG_EXTERNALREF:
7676
fprintf(output, "<externalRef>");
7677
xmlRelaxNGDumpDefines(output, define->content);
7678
fprintf(output, "</externalRef>\n");
7679
break;
7680
case XML_RELAXNG_DATATYPE:
7681
case XML_RELAXNG_VALUE:
7682
TODO break;
7683
case XML_RELAXNG_START:
7684
case XML_RELAXNG_EXCEPT:
7685
case XML_RELAXNG_PARAM:
7686
TODO break;
7687
case XML_RELAXNG_NOOP:
7688
xmlRelaxNGDumpDefines(output, define->content);
7689
break;
7690
}
7691
}
7692
7693
/**
7694
* xmlRelaxNGDumpGrammar:
7695
* @output: the file output
7696
* @grammar: a grammar structure
7697
* @top: is this a top grammar
7698
*
7699
* Dump a RelaxNG structure back
7700
*/
7701
static void
7702
xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7703
{
7704
if (grammar == NULL)
7705
return;
7706
7707
fprintf(output, "<grammar");
7708
if (top)
7709
fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7710
switch (grammar->combine) {
7711
case XML_RELAXNG_COMBINE_UNDEFINED:
7712
break;
7713
case XML_RELAXNG_COMBINE_CHOICE:
7714
fprintf(output, " combine=\"choice\"");
7715
break;
7716
case XML_RELAXNG_COMBINE_INTERLEAVE:
7717
fprintf(output, " combine=\"interleave\"");
7718
break;
7719
default:
7720
fprintf(output, " <!-- invalid combine value -->");
7721
}
7722
fprintf(output, ">\n");
7723
if (grammar->start == NULL) {
7724
fprintf(output, " <!-- grammar had no start -->");
7725
} else {
7726
fprintf(output, "<start>\n");
7727
xmlRelaxNGDumpDefine(output, grammar->start);
7728
fprintf(output, "</start>\n");
7729
}
7730
/* TODO ? Dump the defines ? */
7731
fprintf(output, "</grammar>\n");
7732
}
7733
7734
/**
7735
* xmlRelaxNGDump:
7736
* @output: the file output
7737
* @schema: a schema structure
7738
*
7739
* Dump a RelaxNG structure back
7740
*/
7741
void
7742
xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7743
{
7744
if (output == NULL)
7745
return;
7746
if (schema == NULL) {
7747
fprintf(output, "RelaxNG empty or failed to compile\n");
7748
return;
7749
}
7750
fprintf(output, "RelaxNG: ");
7751
if (schema->doc == NULL) {
7752
fprintf(output, "no document\n");
7753
} else if (schema->doc->URL != NULL) {
7754
fprintf(output, "%s\n", schema->doc->URL);
7755
} else {
7756
fprintf(output, "\n");
7757
}
7758
if (schema->topgrammar == NULL) {
7759
fprintf(output, "RelaxNG has no top grammar\n");
7760
return;
7761
}
7762
xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7763
}
7764
7765
/**
7766
* xmlRelaxNGDumpTree:
7767
* @output: the file output
7768
* @schema: a schema structure
7769
*
7770
* Dump the transformed RelaxNG tree.
7771
*/
7772
void
7773
xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7774
{
7775
if (output == NULL)
7776
return;
7777
if (schema == NULL) {
7778
fprintf(output, "RelaxNG empty or failed to compile\n");
7779
return;
7780
}
7781
if (schema->doc == NULL) {
7782
fprintf(output, "no document\n");
7783
} else {
7784
xmlDocDump(output, schema->doc);
7785
}
7786
}
7787
#endif /* LIBXML_OUTPUT_ENABLED */
7788
7789
/************************************************************************
7790
* *
7791
* Validation of compiled content *
7792
* *
7793
************************************************************************/
7794
static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7795
xmlRelaxNGDefinePtr define);
7796
7797
/**
7798
* xmlRelaxNGValidateCompiledCallback:
7799
* @exec: the regular expression instance
7800
* @token: the token which matched
7801
* @transdata: callback data, the define for the subelement if available
7802
@ @inputdata: callback data, the Relax NG validation context
7803
*
7804
* Handle the callback and if needed validate the element children.
7805
*/
7806
static void
7807
xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7808
const xmlChar * token,
7809
void *transdata, void *inputdata)
7810
{
7811
xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7812
xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7813
int ret;
7814
7815
if (ctxt == NULL) {
7816
fprintf(stderr, "callback on %s missing context\n", token);
7817
return;
7818
}
7819
if (define == NULL) {
7820
if (token[0] == '#')
7821
return;
7822
fprintf(stderr, "callback on %s missing define\n", token);
7823
if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7824
ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7825
return;
7826
}
7827
if (define->type != XML_RELAXNG_ELEMENT) {
7828
fprintf(stderr, "callback on %s define is not element\n", token);
7829
if (ctxt->errNo == XML_RELAXNG_OK)
7830
ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7831
return;
7832
}
7833
ret = xmlRelaxNGValidateDefinition(ctxt, define);
7834
if (ret != 0)
7835
ctxt->perr = ret;
7836
}
7837
7838
/**
7839
* xmlRelaxNGValidateCompiledContent:
7840
* @ctxt: the RelaxNG validation context
7841
* @regexp: the regular expression as compiled
7842
* @content: list of children to test against the regexp
7843
*
7844
* Validate the content model of an element or start using the regexp
7845
*
7846
* Returns 0 in case of success, -1 in case of error.
7847
*/
7848
static int
7849
xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7850
xmlRegexpPtr regexp, xmlNodePtr content)
7851
{
7852
xmlRegExecCtxtPtr exec;
7853
xmlNodePtr cur;
7854
int ret = 0;
7855
int oldperr;
7856
7857
if ((ctxt == NULL) || (regexp == NULL))
7858
return (-1);
7859
oldperr = ctxt->perr;
7860
exec = xmlRegNewExecCtxt(regexp,
7861
xmlRelaxNGValidateCompiledCallback, ctxt);
7862
ctxt->perr = 0;
7863
cur = content;
7864
while (cur != NULL) {
7865
ctxt->state->seq = cur;
7866
switch (cur->type) {
7867
case XML_TEXT_NODE:
7868
case XML_CDATA_SECTION_NODE:
7869
if (xmlIsBlankNode(cur))
7870
break;
7871
ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7872
if (ret < 0) {
7873
VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
7874
cur->parent->name);
7875
}
7876
break;
7877
case XML_ELEMENT_NODE:
7878
if (cur->ns != NULL) {
7879
ret = xmlRegExecPushString2(exec, cur->name,
7880
cur->ns->href, ctxt);
7881
} else {
7882
ret = xmlRegExecPushString(exec, cur->name, ctxt);
7883
}
7884
if (ret < 0) {
7885
VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7886
}
7887
break;
7888
default:
7889
break;
7890
}
7891
if (ret < 0)
7892
break;
7893
/*
7894
* Switch to next element
7895
*/
7896
cur = cur->next;
7897
}
7898
ret = xmlRegExecPushString(exec, NULL, NULL);
7899
if (ret == 1) {
7900
ret = 0;
7901
ctxt->state->seq = NULL;
7902
} else if (ret == 0) {
7903
/*
7904
* TODO: get some of the names needed to exit the current state of exec
7905
*/
7906
VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7907
ret = -1;
7908
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7909
xmlRelaxNGDumpValidError(ctxt);
7910
} else {
7911
ret = -1;
7912
}
7913
xmlRegFreeExecCtxt(exec);
7914
/*
7915
* There might be content model errors outside of the pure
7916
* regexp validation, e.g. for attribute values.
7917
*/
7918
if ((ret == 0) && (ctxt->perr != 0)) {
7919
ret = ctxt->perr;
7920
}
7921
ctxt->perr = oldperr;
7922
return (ret);
7923
}
7924
7925
/************************************************************************
7926
* *
7927
* Progressive validation of when possible *
7928
* *
7929
************************************************************************/
7930
static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7931
xmlRelaxNGDefinePtr defines);
7932
static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
7933
int dolog);
7934
static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
7935
7936
/**
7937
* xmlRelaxNGElemPush:
7938
* @ctxt: the validation context
7939
* @exec: the regexp runtime for the new content model
7940
*
7941
* Push a new regexp for the current node content model on the stack
7942
*
7943
* Returns 0 in case of success and -1 in case of error.
7944
*/
7945
static int
7946
xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
7947
{
7948
if (ctxt->elemTab == NULL) {
7949
ctxt->elemMax = 10;
7950
ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7951
sizeof
7952
(xmlRegExecCtxtPtr));
7953
if (ctxt->elemTab == NULL) {
7954
xmlRngVErrMemory(ctxt, "validating\n");
7955
return (-1);
7956
}
7957
}
7958
if (ctxt->elemNr >= ctxt->elemMax) {
7959
ctxt->elemMax *= 2;
7960
ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
7961
ctxt->elemMax *
7962
sizeof
7963
(xmlRegExecCtxtPtr));
7964
if (ctxt->elemTab == NULL) {
7965
xmlRngVErrMemory(ctxt, "validating\n");
7966
return (-1);
7967
}
7968
}
7969
ctxt->elemTab[ctxt->elemNr++] = exec;
7970
ctxt->elem = exec;
7971
return (0);
7972
}
7973
7974
/**
7975
* xmlRelaxNGElemPop:
7976
* @ctxt: the validation context
7977
*
7978
* Pop the regexp of the current node content model from the stack
7979
*
7980
* Returns the exec or NULL if empty
7981
*/
7982
static xmlRegExecCtxtPtr
7983
xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
7984
{
7985
xmlRegExecCtxtPtr ret;
7986
7987
if (ctxt->elemNr <= 0)
7988
return (NULL);
7989
ctxt->elemNr--;
7990
ret = ctxt->elemTab[ctxt->elemNr];
7991
ctxt->elemTab[ctxt->elemNr] = NULL;
7992
if (ctxt->elemNr > 0)
7993
ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7994
else
7995
ctxt->elem = NULL;
7996
return (ret);
7997
}
7998
7999
/**
8000
* xmlRelaxNGValidateProgressiveCallback:
8001
* @exec: the regular expression instance
8002
* @token: the token which matched
8003
* @transdata: callback data, the define for the subelement if available
8004
@ @inputdata: callback data, the Relax NG validation context
8005
*
8006
* Handle the callback and if needed validate the element children.
8007
* some of the in/out information are passed via the context in @inputdata.
8008
*/
8009
static void
8010
xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8011
ATTRIBUTE_UNUSED,
8012
const xmlChar * token,
8013
void *transdata, void *inputdata)
8014
{
8015
xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
8016
xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
8017
xmlRelaxNGValidStatePtr state, oldstate;
8018
xmlNodePtr node;
8019
int ret = 0, oldflags;
8020
8021
if (ctxt == NULL) {
8022
fprintf(stderr, "callback on %s missing context\n", token);
8023
return;
8024
}
8025
node = ctxt->pnode;
8026
ctxt->pstate = 1;
8027
if (define == NULL) {
8028
if (token[0] == '#')
8029
return;
8030
fprintf(stderr, "callback on %s missing define\n", token);
8031
if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8032
ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8033
ctxt->pstate = -1;
8034
return;
8035
}
8036
if ((ctxt == NULL) || (define == NULL)) {
8037
fprintf(stderr, "callback on %s missing info\n", token);
8038
if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
8039
ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8040
ctxt->pstate = -1;
8041
return;
8042
} else if (define->type != XML_RELAXNG_ELEMENT) {
8043
fprintf(stderr, "callback on %s define is not element\n", token);
8044
if (ctxt->errNo == XML_RELAXNG_OK)
8045
ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
8046
ctxt->pstate = -1;
8047
return;
8048
}
8049
if (node->type != XML_ELEMENT_NODE) {
8050
VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8051
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8052
xmlRelaxNGDumpValidError(ctxt);
8053
ctxt->pstate = -1;
8054
return;
8055
}
8056
if (define->contModel == NULL) {
8057
/*
8058
* this node cannot be validated in a streamable fashion
8059
*/
8060
ctxt->pstate = 0;
8061
ctxt->pdef = define;
8062
return;
8063
}
8064
exec = xmlRegNewExecCtxt(define->contModel,
8065
xmlRelaxNGValidateProgressiveCallback, ctxt);
8066
if (exec == NULL) {
8067
ctxt->pstate = -1;
8068
return;
8069
}
8070
xmlRelaxNGElemPush(ctxt, exec);
8071
8072
/*
8073
* Validate the attributes part of the content.
8074
*/
8075
state = xmlRelaxNGNewValidState(ctxt, node);
8076
if (state == NULL) {
8077
ctxt->pstate = -1;
8078
return;
8079
}
8080
oldstate = ctxt->state;
8081
ctxt->state = state;
8082
if (define->attrs != NULL) {
8083
ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8084
if (ret != 0) {
8085
ctxt->pstate = -1;
8086
VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8087
}
8088
}
8089
if (ctxt->state != NULL) {
8090
ctxt->state->seq = NULL;
8091
ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
8092
if (ret != 0) {
8093
ctxt->pstate = -1;
8094
}
8095
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8096
} else if (ctxt->states != NULL) {
8097
int tmp = -1, i;
8098
8099
oldflags = ctxt->flags;
8100
8101
for (i = 0; i < ctxt->states->nbState; i++) {
8102
state = ctxt->states->tabState[i];
8103
ctxt->state = state;
8104
ctxt->state->seq = NULL;
8105
8106
if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
8107
tmp = 0;
8108
break;
8109
}
8110
}
8111
if (tmp != 0) {
8112
/*
8113
* validation error, log the message for the "best" one
8114
*/
8115
ctxt->flags |= FLAGS_IGNORABLE;
8116
xmlRelaxNGLogBestError(ctxt);
8117
}
8118
for (i = 0; i < ctxt->states->nbState; i++) {
8119
xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
8120
}
8121
xmlRelaxNGFreeStates(ctxt, ctxt->states);
8122
ctxt->states = NULL;
8123
if ((ret == 0) && (tmp == -1))
8124
ctxt->pstate = -1;
8125
ctxt->flags = oldflags;
8126
}
8127
if (ctxt->pstate == -1) {
8128
if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8129
xmlRelaxNGDumpValidError(ctxt);
8130
}
8131
}
8132
ctxt->state = oldstate;
8133
}
8134
8135
/**
8136
* xmlRelaxNGValidatePushElement:
8137
* @ctxt: the validation context
8138
* @doc: a document instance
8139
* @elem: an element instance
8140
*
8141
* Push a new element start on the RelaxNG validation stack.
8142
*
8143
* returns 1 if no validation problem was found or 0 if validating the
8144
* element requires a full node, and -1 in case of error.
8145
*/
8146
int
8147
xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
8148
xmlDocPtr doc ATTRIBUTE_UNUSED,
8149
xmlNodePtr elem)
8150
{
8151
int ret = 1;
8152
8153
if ((ctxt == NULL) || (elem == NULL))
8154
return (-1);
8155
8156
if (ctxt->elem == 0) {
8157
xmlRelaxNGPtr schema;
8158
xmlRelaxNGGrammarPtr grammar;
8159
xmlRegExecCtxtPtr exec;
8160
xmlRelaxNGDefinePtr define;
8161
8162
schema = ctxt->schema;
8163
if (schema == NULL) {
8164
VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8165
return (-1);
8166
}
8167
grammar = schema->topgrammar;
8168
if ((grammar == NULL) || (grammar->start == NULL)) {
8169
VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
8170
return (-1);
8171
}
8172
define = grammar->start;
8173
if (define->contModel == NULL) {
8174
ctxt->pdef = define;
8175
return (0);
8176
}
8177
exec = xmlRegNewExecCtxt(define->contModel,
8178
xmlRelaxNGValidateProgressiveCallback,
8179
ctxt);
8180
if (exec == NULL) {
8181
return (-1);
8182
}
8183
xmlRelaxNGElemPush(ctxt, exec);
8184
}
8185
ctxt->pnode = elem;
8186
ctxt->pstate = 0;
8187
if (elem->ns != NULL) {
8188
ret =
8189
xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
8190
ctxt);
8191
} else {
8192
ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
8193
}
8194
if (ret < 0) {
8195
VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
8196
} else {
8197
if (ctxt->pstate == 0)
8198
ret = 0;
8199
else if (ctxt->pstate < 0)
8200
ret = -1;
8201
else
8202
ret = 1;
8203
}
8204
return (ret);
8205
}
8206
8207
/**
8208
* xmlRelaxNGValidatePushCData:
8209
* @ctxt: the RelaxNG validation context
8210
* @data: some character data read
8211
* @len: the length of the data
8212
*
8213
* check the CData parsed for validation in the current stack
8214
*
8215
* returns 1 if no validation problem was found or -1 otherwise
8216
*/
8217
int
8218
xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
8219
const xmlChar * data, int len ATTRIBUTE_UNUSED)
8220
{
8221
int ret = 1;
8222
8223
if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
8224
return (-1);
8225
8226
while (*data != 0) {
8227
if (!IS_BLANK_CH(*data))
8228
break;
8229
data++;
8230
}
8231
if (*data == 0)
8232
return (1);
8233
8234
ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
8235
if (ret < 0) {
8236
VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
8237
8238
return (-1);
8239
}
8240
return (1);
8241
}
8242
8243
/**
8244
* xmlRelaxNGValidatePopElement:
8245
* @ctxt: the RelaxNG validation context
8246
* @doc: a document instance
8247
* @elem: an element instance
8248
*
8249
* Pop the element end from the RelaxNG validation stack.
8250
*
8251
* returns 1 if no validation problem was found or 0 otherwise
8252
*/
8253
int
8254
xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8255
xmlDocPtr doc ATTRIBUTE_UNUSED,
8256
xmlNodePtr elem)
8257
{
8258
int ret;
8259
xmlRegExecCtxtPtr exec;
8260
8261
if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
8262
return (-1);
8263
/*
8264
* verify that we reached a terminal state of the content model.
8265
*/
8266
exec = xmlRelaxNGElemPop(ctxt);
8267
ret = xmlRegExecPushString(exec, NULL, NULL);
8268
if (ret == 0) {
8269
/*
8270
* TODO: get some of the names needed to exit the current state of exec
8271
*/
8272
VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8273
ret = -1;
8274
} else if (ret < 0) {
8275
ret = -1;
8276
} else {
8277
ret = 1;
8278
}
8279
xmlRegFreeExecCtxt(exec);
8280
return (ret);
8281
}
8282
8283
/**
8284
* xmlRelaxNGValidateFullElement:
8285
* @ctxt: the validation context
8286
* @doc: a document instance
8287
* @elem: an element instance
8288
*
8289
* Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8290
* 0 and the content of the node has been expanded.
8291
*
8292
* returns 1 if no validation problem was found or -1 in case of error.
8293
*/
8294
int
8295
xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8296
xmlDocPtr doc ATTRIBUTE_UNUSED,
8297
xmlNodePtr elem)
8298
{
8299
int ret;
8300
xmlRelaxNGValidStatePtr state;
8301
8302
if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
8303
return (-1);
8304
state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8305
if (state == NULL) {
8306
return (-1);
8307
}
8308
state->seq = elem;
8309
ctxt->state = state;
8310
ctxt->errNo = XML_RELAXNG_OK;
8311
ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8312
if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
8313
ret = -1;
8314
else
8315
ret = 1;
8316
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8317
ctxt->state = NULL;
8318
return (ret);
8319
}
8320
8321
/************************************************************************
8322
* *
8323
* Generic interpreted validation implementation *
8324
* *
8325
************************************************************************/
8326
static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8327
xmlRelaxNGDefinePtr define);
8328
8329
/**
8330
* xmlRelaxNGSkipIgnored:
8331
* @ctxt: a schema validation context
8332
* @node: the top node.
8333
*
8334
* Skip ignorable nodes in that context
8335
*
8336
* Returns the new sibling or NULL in case of error.
8337
*/
8338
static xmlNodePtr
8339
xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8340
xmlNodePtr node)
8341
{
8342
/*
8343
* TODO complete and handle entities
8344
*/
8345
while ((node != NULL) &&
8346
((node->type == XML_COMMENT_NODE) ||
8347
(node->type == XML_PI_NODE) ||
8348
(node->type == XML_XINCLUDE_START) ||
8349
(node->type == XML_XINCLUDE_END) ||
8350
(((node->type == XML_TEXT_NODE) ||
8351
(node->type == XML_CDATA_SECTION_NODE)) &&
8352
((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8353
(IS_BLANK_NODE(node)))))) {
8354
node = node->next;
8355
}
8356
return (node);
8357
}
8358
8359
/**
8360
* xmlRelaxNGNormalize:
8361
* @ctxt: a schema validation context
8362
* @str: the string to normalize
8363
*
8364
* Implements the normalizeWhiteSpace( s ) function from
8365
* section 6.2.9 of the spec
8366
*
8367
* Returns the new string or NULL in case of error.
8368
*/
8369
static xmlChar *
8370
xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
8371
{
8372
xmlChar *ret, *p;
8373
const xmlChar *tmp;
8374
int len;
8375
8376
if (str == NULL)
8377
return (NULL);
8378
tmp = str;
8379
while (*tmp != 0)
8380
tmp++;
8381
len = tmp - str;
8382
8383
ret = (xmlChar *) xmlMallocAtomic(len + 1);
8384
if (ret == NULL) {
8385
xmlRngVErrMemory(ctxt, "validating\n");
8386
return (NULL);
8387
}
8388
p = ret;
8389
while (IS_BLANK_CH(*str))
8390
str++;
8391
while (*str != 0) {
8392
if (IS_BLANK_CH(*str)) {
8393
while (IS_BLANK_CH(*str))
8394
str++;
8395
if (*str == 0)
8396
break;
8397
*p++ = ' ';
8398
} else
8399
*p++ = *str++;
8400
}
8401
*p = 0;
8402
return (ret);
8403
}
8404
8405
/**
8406
* xmlRelaxNGValidateDatatype:
8407
* @ctxt: a Relax-NG validation context
8408
* @value: the string value
8409
* @type: the datatype definition
8410
* @node: the node
8411
*
8412
* Validate the given value against the datatype
8413
*
8414
* Returns 0 if the validation succeeded or an error code.
8415
*/
8416
static int
8417
xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
8418
const xmlChar * value,
8419
xmlRelaxNGDefinePtr define, xmlNodePtr node)
8420
{
8421
int ret, tmp;
8422
xmlRelaxNGTypeLibraryPtr lib;
8423
void *result = NULL;
8424
xmlRelaxNGDefinePtr cur;
8425
8426
if ((define == NULL) || (define->data == NULL)) {
8427
return (-1);
8428
}
8429
lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8430
if (lib->check != NULL) {
8431
if ((define->attrs != NULL) &&
8432
(define->attrs->type == XML_RELAXNG_PARAM)) {
8433
ret =
8434
lib->check(lib->data, define->name, value, &result, node);
8435
} else {
8436
ret = lib->check(lib->data, define->name, value, NULL, node);
8437
}
8438
} else
8439
ret = -1;
8440
if (ret < 0) {
8441
VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
8442
if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8443
lib->freef(lib->data, result);
8444
return (-1);
8445
} else if (ret == 1) {
8446
ret = 0;
8447
} else if (ret == 2) {
8448
VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
8449
} else {
8450
VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
8451
ret = -1;
8452
}
8453
cur = define->attrs;
8454
while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8455
if (lib->facet != NULL) {
8456
tmp = lib->facet(lib->data, define->name, cur->name,
8457
cur->value, value, result);
8458
if (tmp != 0)
8459
ret = -1;
8460
}
8461
cur = cur->next;
8462
}
8463
if ((ret == 0) && (define->content != NULL)) {
8464
const xmlChar *oldvalue, *oldendvalue;
8465
8466
oldvalue = ctxt->state->value;
8467
oldendvalue = ctxt->state->endvalue;
8468
ctxt->state->value = (xmlChar *) value;
8469
ctxt->state->endvalue = NULL;
8470
ret = xmlRelaxNGValidateValue(ctxt, define->content);
8471
ctxt->state->value = (xmlChar *) oldvalue;
8472
ctxt->state->endvalue = (xmlChar *) oldendvalue;
8473
}
8474
if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8475
lib->freef(lib->data, result);
8476
return (ret);
8477
}
8478
8479
/**
8480
* xmlRelaxNGNextValue:
8481
* @ctxt: a Relax-NG validation context
8482
*
8483
* Skip to the next value when validating within a list
8484
*
8485
* Returns 0 if the operation succeeded or an error code.
8486
*/
8487
static int
8488
xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
8489
{
8490
xmlChar *cur;
8491
8492
cur = ctxt->state->value;
8493
if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8494
ctxt->state->value = NULL;
8495
ctxt->state->endvalue = NULL;
8496
return (0);
8497
}
8498
while (*cur != 0)
8499
cur++;
8500
while ((cur != ctxt->state->endvalue) && (*cur == 0))
8501
cur++;
8502
if (cur == ctxt->state->endvalue)
8503
ctxt->state->value = NULL;
8504
else
8505
ctxt->state->value = cur;
8506
return (0);
8507
}
8508
8509
/**
8510
* xmlRelaxNGValidateValueList:
8511
* @ctxt: a Relax-NG validation context
8512
* @defines: the list of definitions to verify
8513
*
8514
* Validate the given set of definitions for the current value
8515
*
8516
* Returns 0 if the validation succeeded or an error code.
8517
*/
8518
static int
8519
xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8520
xmlRelaxNGDefinePtr defines)
8521
{
8522
int ret = 0;
8523
8524
while (defines != NULL) {
8525
ret = xmlRelaxNGValidateValue(ctxt, defines);
8526
if (ret != 0)
8527
break;
8528
defines = defines->next;
8529
}
8530
return (ret);
8531
}
8532
8533
/**
8534
* xmlRelaxNGValidateValue:
8535
* @ctxt: a Relax-NG validation context
8536
* @define: the definition to verify
8537
*
8538
* Validate the given definition for the current value
8539
*
8540
* Returns 0 if the validation succeeded or an error code.
8541
*/
8542
static int
8543
xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8544
xmlRelaxNGDefinePtr define)
8545
{
8546
int ret = 0, oldflags;
8547
xmlChar *value;
8548
8549
value = ctxt->state->value;
8550
switch (define->type) {
8551
case XML_RELAXNG_EMPTY:{
8552
if ((value != NULL) && (value[0] != 0)) {
8553
int idx = 0;
8554
8555
while (IS_BLANK_CH(value[idx]))
8556
idx++;
8557
if (value[idx] != 0)
8558
ret = -1;
8559
}
8560
break;
8561
}
8562
case XML_RELAXNG_TEXT:
8563
break;
8564
case XML_RELAXNG_VALUE:{
8565
if (!xmlStrEqual(value, define->value)) {
8566
if (define->name != NULL) {
8567
xmlRelaxNGTypeLibraryPtr lib;
8568
8569
lib = (xmlRelaxNGTypeLibraryPtr) define->data;
8570
if ((lib != NULL) && (lib->comp != NULL)) {
8571
ret = lib->comp(lib->data, define->name,
8572
define->value, define->node,
8573
(void *) define->attrs,
8574
value, ctxt->state->node);
8575
} else
8576
ret = -1;
8577
if (ret < 0) {
8578
VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
8579
define->name);
8580
return (-1);
8581
} else if (ret == 1) {
8582
ret = 0;
8583
} else {
8584
ret = -1;
8585
}
8586
} else {
8587
xmlChar *nval, *nvalue;
8588
8589
/*
8590
* TODO: trivial optimizations are possible by
8591
* computing at compile-time
8592
*/
8593
nval = xmlRelaxNGNormalize(ctxt, define->value);
8594
nvalue = xmlRelaxNGNormalize(ctxt, value);
8595
8596
if ((nval == NULL) || (nvalue == NULL) ||
8597
(!xmlStrEqual(nval, nvalue)))
8598
ret = -1;
8599
if (nval != NULL)
8600
xmlFree(nval);
8601
if (nvalue != NULL)
8602
xmlFree(nvalue);
8603
}
8604
}
8605
if (ret == 0)
8606
xmlRelaxNGNextValue(ctxt);
8607
break;
8608
}
8609
case XML_RELAXNG_DATATYPE:{
8610
ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8611
ctxt->state->seq);
8612
if (ret == 0)
8613
xmlRelaxNGNextValue(ctxt);
8614
8615
break;
8616
}
8617
case XML_RELAXNG_CHOICE:{
8618
xmlRelaxNGDefinePtr list = define->content;
8619
xmlChar *oldvalue;
8620
8621
oldflags = ctxt->flags;
8622
ctxt->flags |= FLAGS_IGNORABLE;
8623
8624
oldvalue = ctxt->state->value;
8625
while (list != NULL) {
8626
ret = xmlRelaxNGValidateValue(ctxt, list);
8627
if (ret == 0) {
8628
break;
8629
}
8630
ctxt->state->value = oldvalue;
8631
list = list->next;
8632
}
8633
ctxt->flags = oldflags;
8634
if (ret != 0) {
8635
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8636
xmlRelaxNGDumpValidError(ctxt);
8637
} else {
8638
if (ctxt->errNr > 0)
8639
xmlRelaxNGPopErrors(ctxt, 0);
8640
}
8641
break;
8642
}
8643
case XML_RELAXNG_LIST:{
8644
xmlRelaxNGDefinePtr list = define->content;
8645
xmlChar *oldvalue, *oldend, *val, *cur;
8646
8647
oldvalue = ctxt->state->value;
8648
oldend = ctxt->state->endvalue;
8649
8650
val = xmlStrdup(oldvalue);
8651
if (val == NULL) {
8652
val = xmlStrdup(BAD_CAST "");
8653
}
8654
if (val == NULL) {
8655
VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8656
return (-1);
8657
}
8658
cur = val;
8659
while (*cur != 0) {
8660
if (IS_BLANK_CH(*cur)) {
8661
*cur = 0;
8662
cur++;
8663
while (IS_BLANK_CH(*cur))
8664
*cur++ = 0;
8665
} else
8666
cur++;
8667
}
8668
ctxt->state->endvalue = cur;
8669
cur = val;
8670
while ((*cur == 0) && (cur != ctxt->state->endvalue))
8671
cur++;
8672
8673
ctxt->state->value = cur;
8674
8675
while (list != NULL) {
8676
if (ctxt->state->value == ctxt->state->endvalue)
8677
ctxt->state->value = NULL;
8678
ret = xmlRelaxNGValidateValue(ctxt, list);
8679
if (ret != 0) {
8680
break;
8681
}
8682
list = list->next;
8683
}
8684
8685
if ((ret == 0) && (ctxt->state->value != NULL) &&
8686
(ctxt->state->value != ctxt->state->endvalue)) {
8687
VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
8688
ctxt->state->value);
8689
ret = -1;
8690
}
8691
xmlFree(val);
8692
ctxt->state->value = oldvalue;
8693
ctxt->state->endvalue = oldend;
8694
break;
8695
}
8696
case XML_RELAXNG_ONEORMORE:
8697
ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8698
if (ret != 0) {
8699
break;
8700
}
8701
/* Falls through. */
8702
case XML_RELAXNG_ZEROORMORE:{
8703
xmlChar *cur, *temp;
8704
8705
if ((ctxt->state->value == NULL) ||
8706
(*ctxt->state->value == 0)) {
8707
ret = 0;
8708
break;
8709
}
8710
oldflags = ctxt->flags;
8711
ctxt->flags |= FLAGS_IGNORABLE;
8712
cur = ctxt->state->value;
8713
temp = NULL;
8714
while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8715
(temp != cur)) {
8716
temp = cur;
8717
ret =
8718
xmlRelaxNGValidateValueList(ctxt, define->content);
8719
if (ret != 0) {
8720
ctxt->state->value = temp;
8721
ret = 0;
8722
break;
8723
}
8724
cur = ctxt->state->value;
8725
}
8726
ctxt->flags = oldflags;
8727
if (ctxt->errNr > 0)
8728
xmlRelaxNGPopErrors(ctxt, 0);
8729
break;
8730
}
8731
case XML_RELAXNG_OPTIONAL:{
8732
xmlChar *temp;
8733
8734
if ((ctxt->state->value == NULL) ||
8735
(*ctxt->state->value == 0)) {
8736
ret = 0;
8737
break;
8738
}
8739
oldflags = ctxt->flags;
8740
ctxt->flags |= FLAGS_IGNORABLE;
8741
temp = ctxt->state->value;
8742
ret = xmlRelaxNGValidateValue(ctxt, define->content);
8743
ctxt->flags = oldflags;
8744
if (ret != 0) {
8745
ctxt->state->value = temp;
8746
if (ctxt->errNr > 0)
8747
xmlRelaxNGPopErrors(ctxt, 0);
8748
ret = 0;
8749
break;
8750
}
8751
if (ctxt->errNr > 0)
8752
xmlRelaxNGPopErrors(ctxt, 0);
8753
break;
8754
}
8755
case XML_RELAXNG_EXCEPT:{
8756
xmlRelaxNGDefinePtr list;
8757
8758
list = define->content;
8759
while (list != NULL) {
8760
ret = xmlRelaxNGValidateValue(ctxt, list);
8761
if (ret == 0) {
8762
ret = -1;
8763
break;
8764
} else
8765
ret = 0;
8766
list = list->next;
8767
}
8768
break;
8769
}
8770
case XML_RELAXNG_DEF:
8771
case XML_RELAXNG_GROUP:{
8772
xmlRelaxNGDefinePtr list;
8773
8774
list = define->content;
8775
while (list != NULL) {
8776
ret = xmlRelaxNGValidateValue(ctxt, list);
8777
if (ret != 0) {
8778
ret = -1;
8779
break;
8780
} else
8781
ret = 0;
8782
list = list->next;
8783
}
8784
break;
8785
}
8786
case XML_RELAXNG_REF:
8787
case XML_RELAXNG_PARENTREF:
8788
if (define->content == NULL) {
8789
VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8790
ret = -1;
8791
} else {
8792
ret = xmlRelaxNGValidateValue(ctxt, define->content);
8793
}
8794
break;
8795
default:
8796
TODO ret = -1;
8797
}
8798
return (ret);
8799
}
8800
8801
/**
8802
* xmlRelaxNGValidateValueContent:
8803
* @ctxt: a Relax-NG validation context
8804
* @defines: the list of definitions to verify
8805
*
8806
* Validate the given definitions for the current value
8807
*
8808
* Returns 0 if the validation succeeded or an error code.
8809
*/
8810
static int
8811
xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8812
xmlRelaxNGDefinePtr defines)
8813
{
8814
int ret = 0;
8815
8816
while (defines != NULL) {
8817
ret = xmlRelaxNGValidateValue(ctxt, defines);
8818
if (ret != 0)
8819
break;
8820
defines = defines->next;
8821
}
8822
return (ret);
8823
}
8824
8825
/**
8826
* xmlRelaxNGAttributeMatch:
8827
* @ctxt: a Relax-NG validation context
8828
* @define: the definition to check
8829
* @prop: the attribute
8830
*
8831
* Check if the attribute matches the definition nameClass
8832
*
8833
* Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8834
*/
8835
static int
8836
xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8837
xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
8838
{
8839
int ret;
8840
8841
if (define->name != NULL) {
8842
if (!xmlStrEqual(define->name, prop->name))
8843
return (0);
8844
}
8845
if (define->ns != NULL) {
8846
if (define->ns[0] == 0) {
8847
if (prop->ns != NULL)
8848
return (0);
8849
} else {
8850
if ((prop->ns == NULL) ||
8851
(!xmlStrEqual(define->ns, prop->ns->href)))
8852
return (0);
8853
}
8854
}
8855
if (define->nameClass == NULL)
8856
return (1);
8857
define = define->nameClass;
8858
if (define->type == XML_RELAXNG_EXCEPT) {
8859
xmlRelaxNGDefinePtr list;
8860
8861
list = define->content;
8862
while (list != NULL) {
8863
ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8864
if (ret == 1)
8865
return (0);
8866
if (ret < 0)
8867
return (ret);
8868
list = list->next;
8869
}
8870
} else if (define->type == XML_RELAXNG_CHOICE) {
8871
xmlRelaxNGDefinePtr list;
8872
8873
list = define->nameClass;
8874
while (list != NULL) {
8875
ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8876
if (ret == 1)
8877
return (1);
8878
if (ret < 0)
8879
return (ret);
8880
list = list->next;
8881
}
8882
return (0);
8883
} else {
8884
TODO}
8885
return (1);
8886
}
8887
8888
/**
8889
* xmlRelaxNGValidateAttribute:
8890
* @ctxt: a Relax-NG validation context
8891
* @define: the definition to verify
8892
*
8893
* Validate the given attribute definition for that node
8894
*
8895
* Returns 0 if the validation succeeded or an error code.
8896
*/
8897
static int
8898
xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8899
xmlRelaxNGDefinePtr define)
8900
{
8901
int ret = 0, i;
8902
xmlChar *value, *oldvalue;
8903
xmlAttrPtr prop = NULL, tmp;
8904
xmlNodePtr oldseq;
8905
8906
if (ctxt->state->nbAttrLeft <= 0)
8907
return (-1);
8908
if (define->name != NULL) {
8909
for (i = 0; i < ctxt->state->nbAttrs; i++) {
8910
tmp = ctxt->state->attrs[i];
8911
if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8912
if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8913
(tmp->ns == NULL)) ||
8914
((tmp->ns != NULL) &&
8915
(xmlStrEqual(define->ns, tmp->ns->href)))) {
8916
prop = tmp;
8917
break;
8918
}
8919
}
8920
}
8921
if (prop != NULL) {
8922
value = xmlNodeListGetString(prop->doc, prop->children, 1);
8923
oldvalue = ctxt->state->value;
8924
oldseq = ctxt->state->seq;
8925
ctxt->state->seq = (xmlNodePtr) prop;
8926
ctxt->state->value = value;
8927
ctxt->state->endvalue = NULL;
8928
ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8929
if (ctxt->state->value != NULL)
8930
value = ctxt->state->value;
8931
if (value != NULL)
8932
xmlFree(value);
8933
ctxt->state->value = oldvalue;
8934
ctxt->state->seq = oldseq;
8935
if (ret == 0) {
8936
/*
8937
* flag the attribute as processed
8938
*/
8939
ctxt->state->attrs[i] = NULL;
8940
ctxt->state->nbAttrLeft--;
8941
}
8942
} else {
8943
ret = -1;
8944
}
8945
} else {
8946
for (i = 0; i < ctxt->state->nbAttrs; i++) {
8947
tmp = ctxt->state->attrs[i];
8948
if ((tmp != NULL) &&
8949
(xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
8950
prop = tmp;
8951
break;
8952
}
8953
}
8954
if (prop != NULL) {
8955
value = xmlNodeListGetString(prop->doc, prop->children, 1);
8956
oldvalue = ctxt->state->value;
8957
oldseq = ctxt->state->seq;
8958
ctxt->state->seq = (xmlNodePtr) prop;
8959
ctxt->state->value = value;
8960
ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
8961
if (ctxt->state->value != NULL)
8962
value = ctxt->state->value;
8963
if (value != NULL)
8964
xmlFree(value);
8965
ctxt->state->value = oldvalue;
8966
ctxt->state->seq = oldseq;
8967
if (ret == 0) {
8968
/*
8969
* flag the attribute as processed
8970
*/
8971
ctxt->state->attrs[i] = NULL;
8972
ctxt->state->nbAttrLeft--;
8973
}
8974
} else {
8975
ret = -1;
8976
}
8977
}
8978
8979
return (ret);
8980
}
8981
8982
/**
8983
* xmlRelaxNGValidateAttributeList:
8984
* @ctxt: a Relax-NG validation context
8985
* @define: the list of definition to verify
8986
*
8987
* Validate the given node against the list of attribute definitions
8988
*
8989
* Returns 0 if the validation succeeded or an error code.
8990
*/
8991
static int
8992
xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8993
xmlRelaxNGDefinePtr defines)
8994
{
8995
int ret = 0, res;
8996
int needmore = 0;
8997
xmlRelaxNGDefinePtr cur;
8998
8999
cur = defines;
9000
while (cur != NULL) {
9001
if (cur->type == XML_RELAXNG_ATTRIBUTE) {
9002
if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
9003
ret = -1;
9004
} else
9005
needmore = 1;
9006
cur = cur->next;
9007
}
9008
if (!needmore)
9009
return (ret);
9010
cur = defines;
9011
while (cur != NULL) {
9012
if (cur->type != XML_RELAXNG_ATTRIBUTE) {
9013
if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9014
res = xmlRelaxNGValidateDefinition(ctxt, cur);
9015
if (res < 0)
9016
ret = -1;
9017
} else {
9018
VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9019
return (-1);
9020
}
9021
if (res == -1) /* continues on -2 */
9022
break;
9023
}
9024
cur = cur->next;
9025
}
9026
9027
return (ret);
9028
}
9029
9030
/**
9031
* xmlRelaxNGNodeMatchesList:
9032
* @node: the node
9033
* @list: a NULL terminated array of definitions
9034
*
9035
* Check if a node can be matched by one of the definitions
9036
*
9037
* Returns 1 if matches 0 otherwise
9038
*/
9039
static int
9040
xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
9041
{
9042
xmlRelaxNGDefinePtr cur;
9043
int i = 0, tmp;
9044
9045
if ((node == NULL) || (list == NULL))
9046
return (0);
9047
9048
cur = list[i++];
9049
while (cur != NULL) {
9050
if ((node->type == XML_ELEMENT_NODE) &&
9051
(cur->type == XML_RELAXNG_ELEMENT)) {
9052
tmp = xmlRelaxNGElementMatch(NULL, cur, node);
9053
if (tmp == 1)
9054
return (1);
9055
} else if (((node->type == XML_TEXT_NODE) ||
9056
(node->type == XML_CDATA_SECTION_NODE)) &&
9057
((cur->type == XML_RELAXNG_DATATYPE) ||
9058
(cur->type == XML_RELAXNG_LIST) ||
9059
(cur->type == XML_RELAXNG_TEXT) ||
9060
(cur->type == XML_RELAXNG_VALUE))) {
9061
return (1);
9062
}
9063
cur = list[i++];
9064
}
9065
return (0);
9066
}
9067
9068
/**
9069
* xmlRelaxNGValidateInterleave:
9070
* @ctxt: a Relax-NG validation context
9071
* @define: the definition to verify
9072
*
9073
* Validate an interleave definition for a node.
9074
*
9075
* Returns 0 if the validation succeeded or an error code.
9076
*/
9077
static int
9078
xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
9079
xmlRelaxNGDefinePtr define)
9080
{
9081
int ret = 0, i, nbgroups;
9082
int errNr = ctxt->errNr;
9083
int oldflags;
9084
9085
xmlRelaxNGValidStatePtr oldstate;
9086
xmlRelaxNGPartitionPtr partitions;
9087
xmlRelaxNGInterleaveGroupPtr group = NULL;
9088
xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
9089
xmlNodePtr *list = NULL, *lasts = NULL;
9090
9091
if (define->data != NULL) {
9092
partitions = (xmlRelaxNGPartitionPtr) define->data;
9093
nbgroups = partitions->nbgroups;
9094
} else {
9095
VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
9096
return (-1);
9097
}
9098
/*
9099
* Optimizations for MIXED
9100
*/
9101
oldflags = ctxt->flags;
9102
if (define->dflags & IS_MIXED) {
9103
ctxt->flags |= FLAGS_MIXED_CONTENT;
9104
if (nbgroups == 2) {
9105
/*
9106
* this is a pure <mixed> case
9107
*/
9108
if (ctxt->state != NULL)
9109
ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9110
ctxt->state->seq);
9111
if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
9112
ret = xmlRelaxNGValidateDefinition(ctxt,
9113
partitions->groups[1]->
9114
rule);
9115
else
9116
ret = xmlRelaxNGValidateDefinition(ctxt,
9117
partitions->groups[0]->
9118
rule);
9119
if (ret == 0) {
9120
if (ctxt->state != NULL)
9121
ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
9122
ctxt->state->
9123
seq);
9124
}
9125
ctxt->flags = oldflags;
9126
return (ret);
9127
}
9128
}
9129
9130
/*
9131
* Build arrays to store the first and last node of the chain
9132
* pertaining to each group
9133
*/
9134
list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9135
if (list == NULL) {
9136
xmlRngVErrMemory(ctxt, "validating\n");
9137
return (-1);
9138
}
9139
memset(list, 0, nbgroups * sizeof(xmlNodePtr));
9140
lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
9141
if (lasts == NULL) {
9142
xmlRngVErrMemory(ctxt, "validating\n");
9143
return (-1);
9144
}
9145
memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
9146
9147
/*
9148
* Walk the sequence of children finding the right group and
9149
* sorting them in sequences.
9150
*/
9151
cur = ctxt->state->seq;
9152
cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9153
start = cur;
9154
while (cur != NULL) {
9155
ctxt->state->seq = cur;
9156
if ((partitions->triage != NULL) &&
9157
(partitions->flags & IS_DETERMINIST)) {
9158
void *tmp = NULL;
9159
9160
if ((cur->type == XML_TEXT_NODE) ||
9161
(cur->type == XML_CDATA_SECTION_NODE)) {
9162
tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
9163
NULL);
9164
} else if (cur->type == XML_ELEMENT_NODE) {
9165
if (cur->ns != NULL) {
9166
tmp = xmlHashLookup2(partitions->triage, cur->name,
9167
cur->ns->href);
9168
if (tmp == NULL)
9169
tmp = xmlHashLookup2(partitions->triage,
9170
BAD_CAST "#any",
9171
cur->ns->href);
9172
} else
9173
tmp =
9174
xmlHashLookup2(partitions->triage, cur->name,
9175
NULL);
9176
if (tmp == NULL)
9177
tmp =
9178
xmlHashLookup2(partitions->triage, BAD_CAST "#any",
9179
NULL);
9180
}
9181
9182
if (tmp == NULL) {
9183
i = nbgroups;
9184
} else {
9185
i = ((ptrdiff_t) tmp) - 1;
9186
if (partitions->flags & IS_NEEDCHECK) {
9187
group = partitions->groups[i];
9188
if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
9189
i = nbgroups;
9190
}
9191
}
9192
} else {
9193
for (i = 0; i < nbgroups; i++) {
9194
group = partitions->groups[i];
9195
if (group == NULL)
9196
continue;
9197
if (xmlRelaxNGNodeMatchesList(cur, group->defs))
9198
break;
9199
}
9200
}
9201
/*
9202
* We break as soon as an element not matched is found
9203
*/
9204
if (i >= nbgroups) {
9205
break;
9206
}
9207
if (lasts[i] != NULL) {
9208
lasts[i]->next = cur;
9209
lasts[i] = cur;
9210
} else {
9211
list[i] = cur;
9212
lasts[i] = cur;
9213
}
9214
if (cur->next != NULL)
9215
lastchg = cur->next;
9216
else
9217
lastchg = cur;
9218
cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
9219
}
9220
if (ret != 0) {
9221
VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9222
ret = -1;
9223
goto done;
9224
}
9225
lastelem = cur;
9226
oldstate = ctxt->state;
9227
for (i = 0; i < nbgroups; i++) {
9228
ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
9229
if (ctxt->state == NULL) {
9230
ret = -1;
9231
break;
9232
}
9233
group = partitions->groups[i];
9234
if (lasts[i] != NULL) {
9235
last = lasts[i]->next;
9236
lasts[i]->next = NULL;
9237
}
9238
ctxt->state->seq = list[i];
9239
ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
9240
if (ret != 0)
9241
break;
9242
if (ctxt->state != NULL) {
9243
cur = ctxt->state->seq;
9244
cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9245
xmlRelaxNGFreeValidState(ctxt, oldstate);
9246
oldstate = ctxt->state;
9247
ctxt->state = NULL;
9248
if (cur != NULL
9249
/* there's a nasty violation of context-free unambiguities,
9250
since in open-name-class context, interleave in the
9251
production shall finish without caring about anything
9252
else that is OK to follow in that case -- it would
9253
otherwise get marked as "extra content" and would
9254
hence fail the validation, hence this perhaps
9255
dirty attempt to rectify such a situation */
9256
&& (define->parent->type != XML_RELAXNG_DEF
9257
|| !xmlStrEqual(define->parent->name,
9258
(const xmlChar *) "open-name-class"))) {
9259
VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9260
ret = -1;
9261
ctxt->state = oldstate;
9262
goto done;
9263
}
9264
} else if (ctxt->states != NULL) {
9265
int j;
9266
int found = 0;
9267
int best = -1;
9268
int lowattr = -1;
9269
9270
/*
9271
* PBM: what happen if there is attributes checks in the interleaves
9272
*/
9273
9274
for (j = 0; j < ctxt->states->nbState; j++) {
9275
cur = ctxt->states->tabState[j]->seq;
9276
cur = xmlRelaxNGSkipIgnored(ctxt, cur);
9277
if (cur == NULL) {
9278
if (found == 0) {
9279
lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9280
best = j;
9281
}
9282
found = 1;
9283
if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9284
/* try to keep the latest one to mach old heuristic */
9285
lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9286
best = j;
9287
}
9288
if (lowattr == 0)
9289
break;
9290
} else if (found == 0) {
9291
if (lowattr == -1) {
9292
lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9293
best = j;
9294
} else
9295
if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
9296
/* try to keep the latest one to mach old heuristic */
9297
lowattr = ctxt->states->tabState[j]->nbAttrLeft;
9298
best = j;
9299
}
9300
}
9301
}
9302
/*
9303
* BIG PBM: here we pick only one restarting point :-(
9304
*/
9305
if (ctxt->states->nbState > 0) {
9306
xmlRelaxNGFreeValidState(ctxt, oldstate);
9307
if (best != -1) {
9308
oldstate = ctxt->states->tabState[best];
9309
ctxt->states->tabState[best] = NULL;
9310
} else {
9311
oldstate =
9312
ctxt->states->tabState[ctxt->states->nbState - 1];
9313
ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
9314
ctxt->states->nbState--;
9315
}
9316
}
9317
for (j = 0; j < ctxt->states->nbState ; j++) {
9318
xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
9319
}
9320
xmlRelaxNGFreeStates(ctxt, ctxt->states);
9321
ctxt->states = NULL;
9322
if (found == 0) {
9323
if (cur == NULL) {
9324
VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA,
9325
(const xmlChar *) "noname");
9326
} else {
9327
VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
9328
}
9329
ret = -1;
9330
ctxt->state = oldstate;
9331
goto done;
9332
}
9333
} else {
9334
ret = -1;
9335
break;
9336
}
9337
if (lasts[i] != NULL) {
9338
lasts[i]->next = last;
9339
}
9340
}
9341
if (ctxt->state != NULL)
9342
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9343
ctxt->state = oldstate;
9344
ctxt->state->seq = lastelem;
9345
if (ret != 0) {
9346
VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9347
ret = -1;
9348
goto done;
9349
}
9350
9351
done:
9352
ctxt->flags = oldflags;
9353
/*
9354
* builds the next links chain from the prev one
9355
*/
9356
cur = lastchg;
9357
while (cur != NULL) {
9358
if ((cur == start) || (cur->prev == NULL))
9359
break;
9360
cur->prev->next = cur;
9361
cur = cur->prev;
9362
}
9363
if (ret == 0) {
9364
if (ctxt->errNr > errNr)
9365
xmlRelaxNGPopErrors(ctxt, errNr);
9366
}
9367
9368
xmlFree(list);
9369
xmlFree(lasts);
9370
return (ret);
9371
}
9372
9373
/**
9374
* xmlRelaxNGValidateDefinitionList:
9375
* @ctxt: a Relax-NG validation context
9376
* @define: the list of definition to verify
9377
*
9378
* Validate the given node content against the (list) of definitions
9379
*
9380
* Returns 0 if the validation succeeded or an error code.
9381
*/
9382
static int
9383
xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9384
xmlRelaxNGDefinePtr defines)
9385
{
9386
int ret = 0, res;
9387
9388
9389
if (defines == NULL) {
9390
VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
9391
BAD_CAST "NULL definition list");
9392
return (-1);
9393
}
9394
while (defines != NULL) {
9395
if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9396
res = xmlRelaxNGValidateDefinition(ctxt, defines);
9397
if (res < 0)
9398
ret = -1;
9399
} else {
9400
VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9401
return (-1);
9402
}
9403
if (res == -1) /* continues on -2 */
9404
break;
9405
defines = defines->next;
9406
}
9407
9408
return (ret);
9409
}
9410
9411
/**
9412
* xmlRelaxNGElementMatch:
9413
* @ctxt: a Relax-NG validation context
9414
* @define: the definition to check
9415
* @elem: the element
9416
*
9417
* Check if the element matches the definition nameClass
9418
*
9419
* Returns 1 if the element matches, 0 if no, or -1 in case of error
9420
*/
9421
static int
9422
xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9423
xmlRelaxNGDefinePtr define, xmlNodePtr elem)
9424
{
9425
int ret = 0, oldflags = 0;
9426
9427
if (define->name != NULL) {
9428
if (!xmlStrEqual(elem->name, define->name)) {
9429
VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9430
return (0);
9431
}
9432
}
9433
if ((define->ns != NULL) && (define->ns[0] != 0)) {
9434
if (elem->ns == NULL) {
9435
VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
9436
return (0);
9437
} else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9438
VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9439
elem->name, define->ns);
9440
return (0);
9441
}
9442
} else if ((elem->ns != NULL) && (define->ns != NULL) &&
9443
(define->name == NULL)) {
9444
VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
9445
return (0);
9446
} else if ((elem->ns != NULL) && (define->name != NULL)) {
9447
VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
9448
return (0);
9449
}
9450
9451
if (define->nameClass == NULL)
9452
return (1);
9453
9454
define = define->nameClass;
9455
if (define->type == XML_RELAXNG_EXCEPT) {
9456
xmlRelaxNGDefinePtr list;
9457
9458
if (ctxt != NULL) {
9459
oldflags = ctxt->flags;
9460
ctxt->flags |= FLAGS_IGNORABLE;
9461
}
9462
9463
list = define->content;
9464
while (list != NULL) {
9465
ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9466
if (ret == 1) {
9467
if (ctxt != NULL)
9468
ctxt->flags = oldflags;
9469
return (0);
9470
}
9471
if (ret < 0) {
9472
if (ctxt != NULL)
9473
ctxt->flags = oldflags;
9474
return (ret);
9475
}
9476
list = list->next;
9477
}
9478
ret = 1;
9479
if (ctxt != NULL) {
9480
ctxt->flags = oldflags;
9481
}
9482
} else if (define->type == XML_RELAXNG_CHOICE) {
9483
xmlRelaxNGDefinePtr list;
9484
9485
if (ctxt != NULL) {
9486
oldflags = ctxt->flags;
9487
ctxt->flags |= FLAGS_IGNORABLE;
9488
}
9489
9490
list = define->nameClass;
9491
while (list != NULL) {
9492
ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9493
if (ret == 1) {
9494
if (ctxt != NULL)
9495
ctxt->flags = oldflags;
9496
return (1);
9497
}
9498
if (ret < 0) {
9499
if (ctxt != NULL)
9500
ctxt->flags = oldflags;
9501
return (ret);
9502
}
9503
list = list->next;
9504
}
9505
if (ctxt != NULL) {
9506
if (ret != 0) {
9507
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9508
xmlRelaxNGDumpValidError(ctxt);
9509
} else {
9510
if (ctxt->errNr > 0)
9511
xmlRelaxNGPopErrors(ctxt, 0);
9512
}
9513
}
9514
ret = 0;
9515
if (ctxt != NULL) {
9516
ctxt->flags = oldflags;
9517
}
9518
} else {
9519
TODO ret = -1;
9520
}
9521
return (ret);
9522
}
9523
9524
/**
9525
* xmlRelaxNGBestState:
9526
* @ctxt: a Relax-NG validation context
9527
*
9528
* Find the "best" state in the ctxt->states list of states to report
9529
* errors about. I.e. a state with no element left in the child list
9530
* or the one with the less attributes left.
9531
* This is called only if a validation error was detected
9532
*
9533
* Returns the index of the "best" state or -1 in case of error
9534
*/
9535
static int
9536
xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
9537
{
9538
xmlRelaxNGValidStatePtr state;
9539
int i, tmp;
9540
int best = -1;
9541
int value = 1000000;
9542
9543
if ((ctxt == NULL) || (ctxt->states == NULL) ||
9544
(ctxt->states->nbState <= 0))
9545
return (-1);
9546
9547
for (i = 0; i < ctxt->states->nbState; i++) {
9548
state = ctxt->states->tabState[i];
9549
if (state == NULL)
9550
continue;
9551
if (state->seq != NULL) {
9552
if ((best == -1) || (value > 100000)) {
9553
value = 100000;
9554
best = i;
9555
}
9556
} else {
9557
tmp = state->nbAttrLeft;
9558
if ((best == -1) || (value > tmp)) {
9559
value = tmp;
9560
best = i;
9561
}
9562
}
9563
}
9564
return (best);
9565
}
9566
9567
/**
9568
* xmlRelaxNGLogBestError:
9569
* @ctxt: a Relax-NG validation context
9570
*
9571
* Find the "best" state in the ctxt->states list of states to report
9572
* errors about and log it.
9573
*/
9574
static void
9575
xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
9576
{
9577
int best;
9578
9579
if ((ctxt == NULL) || (ctxt->states == NULL) ||
9580
(ctxt->states->nbState <= 0))
9581
return;
9582
9583
best = xmlRelaxNGBestState(ctxt);
9584
if ((best >= 0) && (best < ctxt->states->nbState)) {
9585
ctxt->state = ctxt->states->tabState[best];
9586
9587
xmlRelaxNGValidateElementEnd(ctxt, 1);
9588
}
9589
}
9590
9591
/**
9592
* xmlRelaxNGValidateElementEnd:
9593
* @ctxt: a Relax-NG validation context
9594
* @dolog: indicate that error logging should be done
9595
*
9596
* Validate the end of the element, implements check that
9597
* there is nothing left not consumed in the element content
9598
* or in the attribute list.
9599
*
9600
* Returns 0 if the validation succeeded or an error code.
9601
*/
9602
static int
9603
xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
9604
{
9605
int i;
9606
xmlRelaxNGValidStatePtr state;
9607
9608
state = ctxt->state;
9609
if (state->seq != NULL) {
9610
state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9611
if (state->seq != NULL) {
9612
if (dolog) {
9613
VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9614
state->node->name, state->seq->name);
9615
}
9616
return (-1);
9617
}
9618
}
9619
for (i = 0; i < state->nbAttrs; i++) {
9620
if (state->attrs[i] != NULL) {
9621
if (dolog) {
9622
VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9623
state->attrs[i]->name, state->node->name);
9624
}
9625
return (-1 - i);
9626
}
9627
}
9628
return (0);
9629
}
9630
9631
/**
9632
* xmlRelaxNGValidateState:
9633
* @ctxt: a Relax-NG validation context
9634
* @define: the definition to verify
9635
*
9636
* Validate the current state against the definition
9637
*
9638
* Returns 0 if the validation succeeded or an error code.
9639
*/
9640
static int
9641
xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9642
xmlRelaxNGDefinePtr define)
9643
{
9644
xmlNodePtr node;
9645
int ret = 0, i, tmp, oldflags, errNr;
9646
xmlRelaxNGValidStatePtr oldstate = NULL, state;
9647
9648
if (define == NULL) {
9649
VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9650
return (-1);
9651
}
9652
9653
if (ctxt->state != NULL) {
9654
node = ctxt->state->seq;
9655
} else {
9656
node = NULL;
9657
}
9658
ctxt->depth++;
9659
switch (define->type) {
9660
case XML_RELAXNG_EMPTY:
9661
ret = 0;
9662
break;
9663
case XML_RELAXNG_NOT_ALLOWED:
9664
ret = -1;
9665
break;
9666
case XML_RELAXNG_TEXT:
9667
while ((node != NULL) &&
9668
((node->type == XML_TEXT_NODE) ||
9669
(node->type == XML_COMMENT_NODE) ||
9670
(node->type == XML_PI_NODE) ||
9671
(node->type == XML_CDATA_SECTION_NODE)))
9672
node = node->next;
9673
ctxt->state->seq = node;
9674
break;
9675
case XML_RELAXNG_ELEMENT:
9676
errNr = ctxt->errNr;
9677
node = xmlRelaxNGSkipIgnored(ctxt, node);
9678
if (node == NULL) {
9679
VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9680
ret = -1;
9681
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9682
xmlRelaxNGDumpValidError(ctxt);
9683
break;
9684
}
9685
if (node->type != XML_ELEMENT_NODE) {
9686
VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9687
ret = -1;
9688
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9689
xmlRelaxNGDumpValidError(ctxt);
9690
break;
9691
}
9692
/*
9693
* This node was already validated successfully against
9694
* this definition.
9695
*/
9696
if (node->psvi == define) {
9697
ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9698
if (ctxt->errNr > errNr)
9699
xmlRelaxNGPopErrors(ctxt, errNr);
9700
if (ctxt->errNr != 0) {
9701
while ((ctxt->err != NULL) &&
9702
(((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9703
&& (xmlStrEqual(ctxt->err->arg2, node->name)))
9704
||
9705
((ctxt->err->err ==
9706
XML_RELAXNG_ERR_ELEMEXTRANS)
9707
&& (xmlStrEqual(ctxt->err->arg1, node->name)))
9708
|| (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9709
|| (ctxt->err->err ==
9710
XML_RELAXNG_ERR_NOTELEM)))
9711
xmlRelaxNGValidErrorPop(ctxt);
9712
}
9713
break;
9714
}
9715
9716
ret = xmlRelaxNGElementMatch(ctxt, define, node);
9717
if (ret <= 0) {
9718
ret = -1;
9719
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9720
xmlRelaxNGDumpValidError(ctxt);
9721
break;
9722
}
9723
ret = 0;
9724
if (ctxt->errNr != 0) {
9725
if (ctxt->errNr > errNr)
9726
xmlRelaxNGPopErrors(ctxt, errNr);
9727
while ((ctxt->err != NULL) &&
9728
(((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9729
(xmlStrEqual(ctxt->err->arg2, node->name))) ||
9730
((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9731
(xmlStrEqual(ctxt->err->arg1, node->name))) ||
9732
(ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9733
(ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9734
xmlRelaxNGValidErrorPop(ctxt);
9735
}
9736
errNr = ctxt->errNr;
9737
9738
oldflags = ctxt->flags;
9739
if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9740
ctxt->flags -= FLAGS_MIXED_CONTENT;
9741
}
9742
state = xmlRelaxNGNewValidState(ctxt, node);
9743
if (state == NULL) {
9744
ret = -1;
9745
if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9746
xmlRelaxNGDumpValidError(ctxt);
9747
break;
9748
}
9749
9750
oldstate = ctxt->state;
9751
ctxt->state = state;
9752
if (define->attrs != NULL) {
9753
tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9754
if (tmp != 0) {
9755
ret = -1;
9756
VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9757
}
9758
}
9759
if (define->contModel != NULL) {
9760
xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9761
xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9762
xmlNodePtr nseq;
9763
9764
nstate = xmlRelaxNGNewValidState(ctxt, node);
9765
ctxt->state = nstate;
9766
ctxt->states = NULL;
9767
9768
tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9769
define->contModel,
9770
ctxt->state->seq);
9771
nseq = ctxt->state->seq;
9772
ctxt->state = tmpstate;
9773
ctxt->states = tmpstates;
9774
xmlRelaxNGFreeValidState(ctxt, nstate);
9775
9776
if (tmp != 0)
9777
ret = -1;
9778
9779
if (ctxt->states != NULL) {
9780
tmp = -1;
9781
9782
for (i = 0; i < ctxt->states->nbState; i++) {
9783
state = ctxt->states->tabState[i];
9784
ctxt->state = state;
9785
ctxt->state->seq = nseq;
9786
9787
if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
9788
tmp = 0;
9789
break;
9790
}
9791
}
9792
if (tmp != 0) {
9793
/*
9794
* validation error, log the message for the "best" one
9795
*/
9796
ctxt->flags |= FLAGS_IGNORABLE;
9797
xmlRelaxNGLogBestError(ctxt);
9798
}
9799
for (i = 0; i < ctxt->states->nbState; i++) {
9800
xmlRelaxNGFreeValidState(ctxt,
9801
ctxt->states->
9802
tabState[i]);
9803
}
9804
xmlRelaxNGFreeStates(ctxt, ctxt->states);
9805
ctxt->flags = oldflags;
9806
ctxt->states = NULL;
9807
if ((ret == 0) && (tmp == -1))
9808
ret = -1;
9809
} else {
9810
state = ctxt->state;
9811
if (ctxt->state != NULL)
9812
ctxt->state->seq = nseq;
9813
if (ret == 0)
9814
ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
9815
xmlRelaxNGFreeValidState(ctxt, state);
9816
}
9817
} else {
9818
if (define->content != NULL) {
9819
tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9820
define->
9821
content);
9822
if (tmp != 0) {
9823
ret = -1;
9824
if (ctxt->state == NULL) {
9825
ctxt->state = oldstate;
9826
VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9827
node->name);
9828
ctxt->state = NULL;
9829
} else {
9830
VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9831
node->name);
9832
}
9833
9834
}
9835
}
9836
if (ctxt->states != NULL) {
9837
tmp = -1;
9838
9839
for (i = 0; i < ctxt->states->nbState; i++) {
9840
state = ctxt->states->tabState[i];
9841
ctxt->state = state;
9842
9843
if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
9844
tmp = 0;
9845
break;
9846
}
9847
}
9848
if (tmp != 0) {
9849
/*
9850
* validation error, log the message for the "best" one
9851
*/
9852
ctxt->flags |= FLAGS_IGNORABLE;
9853
xmlRelaxNGLogBestError(ctxt);
9854
}
9855
for (i = 0; i < ctxt->states->nbState; i++) {
9856
xmlRelaxNGFreeValidState(ctxt,
9857
ctxt->states->tabState[i]);
9858
ctxt->states->tabState[i] = NULL;
9859
}
9860
xmlRelaxNGFreeStates(ctxt, ctxt->states);
9861
ctxt->flags = oldflags;
9862
ctxt->states = NULL;
9863
if ((ret == 0) && (tmp == -1))
9864
ret = -1;
9865
} else {
9866
state = ctxt->state;
9867
if (ret == 0)
9868
ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
9869
xmlRelaxNGFreeValidState(ctxt, state);
9870
}
9871
}
9872
if (ret == 0) {
9873
node->psvi = define;
9874
}
9875
ctxt->flags = oldflags;
9876
ctxt->state = oldstate;
9877
if (oldstate != NULL)
9878
oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9879
if (ret != 0) {
9880
if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9881
xmlRelaxNGDumpValidError(ctxt);
9882
ret = 0;
9883
#if 0
9884
} else {
9885
ret = -2;
9886
#endif
9887
}
9888
} else {
9889
if (ctxt->errNr > errNr)
9890
xmlRelaxNGPopErrors(ctxt, errNr);
9891
}
9892
9893
break;
9894
case XML_RELAXNG_OPTIONAL:{
9895
errNr = ctxt->errNr;
9896
oldflags = ctxt->flags;
9897
ctxt->flags |= FLAGS_IGNORABLE;
9898
oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9899
ret =
9900
xmlRelaxNGValidateDefinitionList(ctxt,
9901
define->content);
9902
if (ret != 0) {
9903
if (ctxt->state != NULL)
9904
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9905
ctxt->state = oldstate;
9906
ctxt->flags = oldflags;
9907
ret = 0;
9908
if (ctxt->errNr > errNr)
9909
xmlRelaxNGPopErrors(ctxt, errNr);
9910
break;
9911
}
9912
if (ctxt->states != NULL) {
9913
xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9914
} else {
9915
ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9916
if (ctxt->states == NULL) {
9917
xmlRelaxNGFreeValidState(ctxt, oldstate);
9918
ctxt->flags = oldflags;
9919
ret = -1;
9920
if (ctxt->errNr > errNr)
9921
xmlRelaxNGPopErrors(ctxt, errNr);
9922
break;
9923
}
9924
xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9925
xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9926
ctxt->state = NULL;
9927
}
9928
ctxt->flags = oldflags;
9929
ret = 0;
9930
if (ctxt->errNr > errNr)
9931
xmlRelaxNGPopErrors(ctxt, errNr);
9932
break;
9933
}
9934
case XML_RELAXNG_ONEORMORE:
9935
errNr = ctxt->errNr;
9936
ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9937
if (ret != 0) {
9938
break;
9939
}
9940
if (ctxt->errNr > errNr)
9941
xmlRelaxNGPopErrors(ctxt, errNr);
9942
/* Falls through. */
9943
case XML_RELAXNG_ZEROORMORE:{
9944
int progress;
9945
xmlRelaxNGStatesPtr states = NULL, res = NULL;
9946
int base, j;
9947
9948
errNr = ctxt->errNr;
9949
res = xmlRelaxNGNewStates(ctxt, 1);
9950
if (res == NULL) {
9951
ret = -1;
9952
break;
9953
}
9954
/*
9955
* All the input states are also exit states
9956
*/
9957
if (ctxt->state != NULL) {
9958
xmlRelaxNGAddStates(ctxt, res,
9959
xmlRelaxNGCopyValidState(ctxt,
9960
ctxt->
9961
state));
9962
} else {
9963
for (j = 0; j < ctxt->states->nbState; j++) {
9964
xmlRelaxNGAddStates(ctxt, res,
9965
xmlRelaxNGCopyValidState(ctxt,
9966
ctxt->states->tabState[j]));
9967
}
9968
}
9969
oldflags = ctxt->flags;
9970
ctxt->flags |= FLAGS_IGNORABLE;
9971
do {
9972
progress = 0;
9973
base = res->nbState;
9974
9975
if (ctxt->states != NULL) {
9976
states = ctxt->states;
9977
for (i = 0; i < states->nbState; i++) {
9978
ctxt->state = states->tabState[i];
9979
ctxt->states = NULL;
9980
ret = xmlRelaxNGValidateDefinitionList(ctxt,
9981
define->
9982
content);
9983
if (ret == 0) {
9984
if (ctxt->state != NULL) {
9985
tmp = xmlRelaxNGAddStates(ctxt, res,
9986
ctxt->state);
9987
ctxt->state = NULL;
9988
if (tmp == 1)
9989
progress = 1;
9990
} else if (ctxt->states != NULL) {
9991
for (j = 0; j < ctxt->states->nbState;
9992
j++) {
9993
tmp =
9994
xmlRelaxNGAddStates(ctxt, res,
9995
ctxt->states->tabState[j]);
9996
if (tmp == 1)
9997
progress = 1;
9998
}
9999
xmlRelaxNGFreeStates(ctxt,
10000
ctxt->states);
10001
ctxt->states = NULL;
10002
}
10003
} else {
10004
if (ctxt->state != NULL) {
10005
xmlRelaxNGFreeValidState(ctxt,
10006
ctxt->state);
10007
ctxt->state = NULL;
10008
}
10009
}
10010
}
10011
} else {
10012
ret = xmlRelaxNGValidateDefinitionList(ctxt,
10013
define->
10014
content);
10015
if (ret != 0) {
10016
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10017
ctxt->state = NULL;
10018
} else {
10019
base = res->nbState;
10020
if (ctxt->state != NULL) {
10021
tmp = xmlRelaxNGAddStates(ctxt, res,
10022
ctxt->state);
10023
ctxt->state = NULL;
10024
if (tmp == 1)
10025
progress = 1;
10026
} else if (ctxt->states != NULL) {
10027
for (j = 0; j < ctxt->states->nbState; j++) {
10028
tmp = xmlRelaxNGAddStates(ctxt, res,
10029
ctxt->states->tabState[j]);
10030
if (tmp == 1)
10031
progress = 1;
10032
}
10033
if (states == NULL) {
10034
states = ctxt->states;
10035
} else {
10036
xmlRelaxNGFreeStates(ctxt,
10037
ctxt->states);
10038
}
10039
ctxt->states = NULL;
10040
}
10041
}
10042
}
10043
if (progress) {
10044
/*
10045
* Collect all the new nodes added at that step
10046
* and make them the new node set
10047
*/
10048
if (res->nbState - base == 1) {
10049
ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10050
res->
10051
tabState
10052
[base]);
10053
} else {
10054
if (states == NULL) {
10055
xmlRelaxNGNewStates(ctxt,
10056
res->nbState - base);
10057
states = ctxt->states;
10058
if (states == NULL) {
10059
progress = 0;
10060
break;
10061
}
10062
}
10063
states->nbState = 0;
10064
for (i = base; i < res->nbState; i++)
10065
xmlRelaxNGAddStates(ctxt, states,
10066
xmlRelaxNGCopyValidState
10067
(ctxt, res->tabState[i]));
10068
ctxt->states = states;
10069
}
10070
}
10071
} while (progress == 1);
10072
if (states != NULL) {
10073
xmlRelaxNGFreeStates(ctxt, states);
10074
}
10075
ctxt->states = res;
10076
ctxt->flags = oldflags;
10077
#if 0
10078
/*
10079
* errors may have to be propagated back...
10080
*/
10081
if (ctxt->errNr > errNr)
10082
xmlRelaxNGPopErrors(ctxt, errNr);
10083
#endif
10084
ret = 0;
10085
break;
10086
}
10087
case XML_RELAXNG_CHOICE:{
10088
xmlRelaxNGDefinePtr list = NULL;
10089
xmlRelaxNGStatesPtr states = NULL;
10090
10091
node = xmlRelaxNGSkipIgnored(ctxt, node);
10092
10093
errNr = ctxt->errNr;
10094
if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10095
(node != NULL)) {
10096
/*
10097
* node == NULL can't be optimized since IS_TRIABLE
10098
* doesn't account for choice which may lead to
10099
* only attributes.
10100
*/
10101
xmlHashTablePtr triage =
10102
(xmlHashTablePtr) define->data;
10103
10104
/*
10105
* Something we can optimize cleanly there is only one
10106
* possible branch out !
10107
*/
10108
if ((node->type == XML_TEXT_NODE) ||
10109
(node->type == XML_CDATA_SECTION_NODE)) {
10110
list =
10111
xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10112
} else if (node->type == XML_ELEMENT_NODE) {
10113
if (node->ns != NULL) {
10114
list = xmlHashLookup2(triage, node->name,
10115
node->ns->href);
10116
if (list == NULL)
10117
list =
10118
xmlHashLookup2(triage, BAD_CAST "#any",
10119
node->ns->href);
10120
} else
10121
list =
10122
xmlHashLookup2(triage, node->name, NULL);
10123
if (list == NULL)
10124
list =
10125
xmlHashLookup2(triage, BAD_CAST "#any",
10126
NULL);
10127
}
10128
if (list == NULL) {
10129
ret = -1;
10130
VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
10131
break;
10132
}
10133
ret = xmlRelaxNGValidateDefinition(ctxt, list);
10134
if (ret == 0) {
10135
}
10136
break;
10137
}
10138
10139
list = define->content;
10140
oldflags = ctxt->flags;
10141
ctxt->flags |= FLAGS_IGNORABLE;
10142
10143
while (list != NULL) {
10144
oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10145
ret = xmlRelaxNGValidateDefinition(ctxt, list);
10146
if (ret == 0) {
10147
if (states == NULL) {
10148
states = xmlRelaxNGNewStates(ctxt, 1);
10149
}
10150
if (ctxt->state != NULL) {
10151
xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10152
} else if (ctxt->states != NULL) {
10153
for (i = 0; i < ctxt->states->nbState; i++) {
10154
xmlRelaxNGAddStates(ctxt, states,
10155
ctxt->states->
10156
tabState[i]);
10157
}
10158
xmlRelaxNGFreeStates(ctxt, ctxt->states);
10159
ctxt->states = NULL;
10160
}
10161
} else {
10162
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10163
}
10164
ctxt->state = oldstate;
10165
list = list->next;
10166
}
10167
if (states != NULL) {
10168
xmlRelaxNGFreeValidState(ctxt, oldstate);
10169
ctxt->states = states;
10170
ctxt->state = NULL;
10171
ret = 0;
10172
} else {
10173
ctxt->states = NULL;
10174
}
10175
ctxt->flags = oldflags;
10176
if (ret != 0) {
10177
if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10178
xmlRelaxNGDumpValidError(ctxt);
10179
}
10180
} else {
10181
if (ctxt->errNr > errNr)
10182
xmlRelaxNGPopErrors(ctxt, errNr);
10183
}
10184
break;
10185
}
10186
case XML_RELAXNG_DEF:
10187
case XML_RELAXNG_GROUP:
10188
ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10189
break;
10190
case XML_RELAXNG_INTERLEAVE:
10191
ret = xmlRelaxNGValidateInterleave(ctxt, define);
10192
break;
10193
case XML_RELAXNG_ATTRIBUTE:
10194
ret = xmlRelaxNGValidateAttribute(ctxt, define);
10195
break;
10196
case XML_RELAXNG_START:
10197
case XML_RELAXNG_NOOP:
10198
case XML_RELAXNG_REF:
10199
case XML_RELAXNG_EXTERNALREF:
10200
case XML_RELAXNG_PARENTREF:
10201
ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10202
break;
10203
case XML_RELAXNG_DATATYPE:{
10204
xmlNodePtr child;
10205
xmlChar *content = NULL;
10206
10207
child = node;
10208
while (child != NULL) {
10209
if (child->type == XML_ELEMENT_NODE) {
10210
VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10211
node->parent->name);
10212
ret = -1;
10213
break;
10214
} else if ((child->type == XML_TEXT_NODE) ||
10215
(child->type == XML_CDATA_SECTION_NODE)) {
10216
content = xmlStrcat(content, child->content);
10217
}
10218
/* TODO: handle entities ... */
10219
child = child->next;
10220
}
10221
if (ret == -1) {
10222
if (content != NULL)
10223
xmlFree(content);
10224
break;
10225
}
10226
if (content == NULL) {
10227
content = xmlStrdup(BAD_CAST "");
10228
if (content == NULL) {
10229
xmlRngVErrMemory(ctxt, "validating\n");
10230
ret = -1;
10231
break;
10232
}
10233
}
10234
ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10235
ctxt->state->seq);
10236
if (ret == -1) {
10237
VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10238
} else if (ret == 0) {
10239
ctxt->state->seq = NULL;
10240
}
10241
if (content != NULL)
10242
xmlFree(content);
10243
break;
10244
}
10245
case XML_RELAXNG_VALUE:{
10246
xmlChar *content = NULL;
10247
xmlChar *oldvalue;
10248
xmlNodePtr child;
10249
10250
child = node;
10251
while (child != NULL) {
10252
if (child->type == XML_ELEMENT_NODE) {
10253
VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10254
node->parent->name);
10255
ret = -1;
10256
break;
10257
} else if ((child->type == XML_TEXT_NODE) ||
10258
(child->type == XML_CDATA_SECTION_NODE)) {
10259
content = xmlStrcat(content, child->content);
10260
}
10261
/* TODO: handle entities ... */
10262
child = child->next;
10263
}
10264
if (ret == -1) {
10265
if (content != NULL)
10266
xmlFree(content);
10267
break;
10268
}
10269
if (content == NULL) {
10270
content = xmlStrdup(BAD_CAST "");
10271
if (content == NULL) {
10272
xmlRngVErrMemory(ctxt, "validating\n");
10273
ret = -1;
10274
break;
10275
}
10276
}
10277
oldvalue = ctxt->state->value;
10278
ctxt->state->value = content;
10279
ret = xmlRelaxNGValidateValue(ctxt, define);
10280
ctxt->state->value = oldvalue;
10281
if (ret == -1) {
10282
VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10283
} else if (ret == 0) {
10284
ctxt->state->seq = NULL;
10285
}
10286
if (content != NULL)
10287
xmlFree(content);
10288
break;
10289
}
10290
case XML_RELAXNG_LIST:{
10291
xmlChar *content;
10292
xmlNodePtr child;
10293
xmlChar *oldvalue, *oldendvalue;
10294
int len;
10295
10296
/*
10297
* Make sure it's only text nodes
10298
*/
10299
10300
content = NULL;
10301
child = node;
10302
while (child != NULL) {
10303
if (child->type == XML_ELEMENT_NODE) {
10304
VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10305
node->parent->name);
10306
ret = -1;
10307
break;
10308
} else if ((child->type == XML_TEXT_NODE) ||
10309
(child->type == XML_CDATA_SECTION_NODE)) {
10310
content = xmlStrcat(content, child->content);
10311
}
10312
/* TODO: handle entities ... */
10313
child = child->next;
10314
}
10315
if (ret == -1) {
10316
if (content != NULL)
10317
xmlFree(content);
10318
break;
10319
}
10320
if (content == NULL) {
10321
content = xmlStrdup(BAD_CAST "");
10322
if (content == NULL) {
10323
xmlRngVErrMemory(ctxt, "validating\n");
10324
ret = -1;
10325
break;
10326
}
10327
}
10328
len = xmlStrlen(content);
10329
oldvalue = ctxt->state->value;
10330
oldendvalue = ctxt->state->endvalue;
10331
ctxt->state->value = content;
10332
ctxt->state->endvalue = content + len;
10333
ret = xmlRelaxNGValidateValue(ctxt, define);
10334
ctxt->state->value = oldvalue;
10335
ctxt->state->endvalue = oldendvalue;
10336
if (ret == -1) {
10337
VALID_ERR(XML_RELAXNG_ERR_LIST);
10338
} else if ((ret == 0) && (node != NULL)) {
10339
ctxt->state->seq = node->next;
10340
}
10341
if (content != NULL)
10342
xmlFree(content);
10343
break;
10344
}
10345
case XML_RELAXNG_EXCEPT:
10346
case XML_RELAXNG_PARAM:
10347
TODO ret = -1;
10348
break;
10349
}
10350
ctxt->depth--;
10351
return (ret);
10352
}
10353
10354
/**
10355
* xmlRelaxNGValidateDefinition:
10356
* @ctxt: a Relax-NG validation context
10357
* @define: the definition to verify
10358
*
10359
* Validate the current node lists against the definition
10360
*
10361
* Returns 0 if the validation succeeded or an error code.
10362
*/
10363
static int
10364
xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10365
xmlRelaxNGDefinePtr define)
10366
{
10367
xmlRelaxNGStatesPtr states, res;
10368
int i, j, k, ret, oldflags;
10369
10370
/*
10371
* We should NOT have both ctxt->state and ctxt->states
10372
*/
10373
if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10374
TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10375
ctxt->state = NULL;
10376
}
10377
10378
if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10379
if (ctxt->states != NULL) {
10380
ctxt->state = ctxt->states->tabState[0];
10381
xmlRelaxNGFreeStates(ctxt, ctxt->states);
10382
ctxt->states = NULL;
10383
}
10384
ret = xmlRelaxNGValidateState(ctxt, define);
10385
if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10386
TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10387
ctxt->state = NULL;
10388
}
10389
if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10390
ctxt->state = ctxt->states->tabState[0];
10391
xmlRelaxNGFreeStates(ctxt, ctxt->states);
10392
ctxt->states = NULL;
10393
}
10394
return (ret);
10395
}
10396
10397
states = ctxt->states;
10398
ctxt->states = NULL;
10399
res = NULL;
10400
j = 0;
10401
oldflags = ctxt->flags;
10402
ctxt->flags |= FLAGS_IGNORABLE;
10403
for (i = 0; i < states->nbState; i++) {
10404
ctxt->state = states->tabState[i];
10405
ctxt->states = NULL;
10406
ret = xmlRelaxNGValidateState(ctxt, define);
10407
/*
10408
* We should NOT have both ctxt->state and ctxt->states
10409
*/
10410
if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10411
TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10412
ctxt->state = NULL;
10413
}
10414
if (ret == 0) {
10415
if (ctxt->states == NULL) {
10416
if (res != NULL) {
10417
/* add the state to the container */
10418
xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10419
ctxt->state = NULL;
10420
} else {
10421
/* add the state directly in states */
10422
states->tabState[j++] = ctxt->state;
10423
ctxt->state = NULL;
10424
}
10425
} else {
10426
if (res == NULL) {
10427
/* make it the new container and copy other results */
10428
res = ctxt->states;
10429
ctxt->states = NULL;
10430
for (k = 0; k < j; k++)
10431
xmlRelaxNGAddStates(ctxt, res,
10432
states->tabState[k]);
10433
} else {
10434
/* add all the new results to res and reff the container */
10435
for (k = 0; k < ctxt->states->nbState; k++)
10436
xmlRelaxNGAddStates(ctxt, res,
10437
ctxt->states->tabState[k]);
10438
xmlRelaxNGFreeStates(ctxt, ctxt->states);
10439
ctxt->states = NULL;
10440
}
10441
}
10442
} else {
10443
if (ctxt->state != NULL) {
10444
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10445
ctxt->state = NULL;
10446
} else if (ctxt->states != NULL) {
10447
for (k = 0; k < ctxt->states->nbState; k++)
10448
xmlRelaxNGFreeValidState(ctxt,
10449
ctxt->states->tabState[k]);
10450
xmlRelaxNGFreeStates(ctxt, ctxt->states);
10451
ctxt->states = NULL;
10452
}
10453
}
10454
}
10455
ctxt->flags = oldflags;
10456
if (res != NULL) {
10457
xmlRelaxNGFreeStates(ctxt, states);
10458
ctxt->states = res;
10459
ret = 0;
10460
} else if (j > 1) {
10461
states->nbState = j;
10462
ctxt->states = states;
10463
ret = 0;
10464
} else if (j == 1) {
10465
ctxt->state = states->tabState[0];
10466
xmlRelaxNGFreeStates(ctxt, states);
10467
ret = 0;
10468
} else {
10469
ret = -1;
10470
xmlRelaxNGFreeStates(ctxt, states);
10471
if (ctxt->states != NULL) {
10472
xmlRelaxNGFreeStates(ctxt, ctxt->states);
10473
ctxt->states = NULL;
10474
}
10475
}
10476
if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10477
TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10478
ctxt->state = NULL;
10479
}
10480
return (ret);
10481
}
10482
10483
/**
10484
* xmlRelaxNGValidateDocument:
10485
* @ctxt: a Relax-NG validation context
10486
* @doc: the document
10487
*
10488
* Validate the given document
10489
*
10490
* Returns 0 if the validation succeeded or an error code.
10491
*/
10492
static int
10493
xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10494
{
10495
int ret;
10496
xmlRelaxNGPtr schema;
10497
xmlRelaxNGGrammarPtr grammar;
10498
xmlRelaxNGValidStatePtr state;
10499
xmlNodePtr node;
10500
10501
if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10502
return (-1);
10503
10504
ctxt->errNo = XML_RELAXNG_OK;
10505
schema = ctxt->schema;
10506
grammar = schema->topgrammar;
10507
if (grammar == NULL) {
10508
VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10509
return (-1);
10510
}
10511
state = xmlRelaxNGNewValidState(ctxt, NULL);
10512
ctxt->state = state;
10513
ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
10514
if ((ctxt->state != NULL) && (state->seq != NULL)) {
10515
state = ctxt->state;
10516
node = state->seq;
10517
node = xmlRelaxNGSkipIgnored(ctxt, node);
10518
if (node != NULL) {
10519
if (ret != -1) {
10520
VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10521
ret = -1;
10522
}
10523
}
10524
} else if (ctxt->states != NULL) {
10525
int i;
10526
int tmp = -1;
10527
10528
for (i = 0; i < ctxt->states->nbState; i++) {
10529
state = ctxt->states->tabState[i];
10530
node = state->seq;
10531
node = xmlRelaxNGSkipIgnored(ctxt, node);
10532
if (node == NULL)
10533
tmp = 0;
10534
xmlRelaxNGFreeValidState(ctxt, state);
10535
}
10536
if (tmp == -1) {
10537
if (ret != -1) {
10538
VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10539
ret = -1;
10540
}
10541
}
10542
}
10543
if (ctxt->state != NULL) {
10544
xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10545
ctxt->state = NULL;
10546
}
10547
if (ret != 0)
10548
xmlRelaxNGDumpValidError(ctxt);
10549
#ifdef LIBXML_VALID_ENABLED
10550
if (ctxt->idref == 1) {
10551
xmlValidCtxt vctxt;
10552
10553
memset(&vctxt, 0, sizeof(xmlValidCtxt));
10554
vctxt.valid = 1;
10555
vctxt.error = ctxt->error;
10556
vctxt.warning = ctxt->warning;
10557
vctxt.userData = ctxt->userData;
10558
10559
if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10560
ret = -1;
10561
}
10562
#endif /* LIBXML_VALID_ENABLED */
10563
if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10564
ret = -1;
10565
10566
return (ret);
10567
}
10568
10569
/**
10570
* xmlRelaxNGCleanPSVI:
10571
* @node: an input element or document
10572
*
10573
* Call this routine to speed up XPath computation on static documents.
10574
* This stamps all the element nodes with the document order
10575
* Like for line information, the order is kept in the element->content
10576
* field, the value stored is actually - the node number (starting at -1)
10577
* to be able to differentiate from line numbers.
10578
*
10579
* Returns the number of elements found in the document or -1 in case
10580
* of error.
10581
*/
10582
static void
10583
xmlRelaxNGCleanPSVI(xmlNodePtr node) {
10584
xmlNodePtr cur;
10585
10586
if ((node == NULL) ||
10587
((node->type != XML_ELEMENT_NODE) &&
10588
(node->type != XML_DOCUMENT_NODE) &&
10589
(node->type != XML_HTML_DOCUMENT_NODE)))
10590
return;
10591
if (node->type == XML_ELEMENT_NODE)
10592
node->psvi = NULL;
10593
10594
cur = node->children;
10595
while (cur != NULL) {
10596
if (cur->type == XML_ELEMENT_NODE) {
10597
cur->psvi = NULL;
10598
if (cur->children != NULL) {
10599
cur = cur->children;
10600
continue;
10601
}
10602
}
10603
if (cur->next != NULL) {
10604
cur = cur->next;
10605
continue;
10606
}
10607
do {
10608
cur = cur->parent;
10609
if (cur == NULL)
10610
break;
10611
if (cur == node) {
10612
cur = NULL;
10613
break;
10614
}
10615
if (cur->next != NULL) {
10616
cur = cur->next;
10617
break;
10618
}
10619
} while (cur != NULL);
10620
}
10621
return;
10622
}
10623
/************************************************************************
10624
* *
10625
* Validation interfaces *
10626
* *
10627
************************************************************************/
10628
10629
/**
10630
* xmlRelaxNGNewValidCtxt:
10631
* @schema: a precompiled XML RelaxNGs
10632
*
10633
* Create an XML RelaxNGs validation context based on the given schema
10634
*
10635
* Returns the validation context or NULL in case of error
10636
*/
10637
xmlRelaxNGValidCtxtPtr
10638
xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10639
{
10640
xmlRelaxNGValidCtxtPtr ret;
10641
10642
ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10643
if (ret == NULL) {
10644
xmlRngVErrMemory(NULL, "building context\n");
10645
return (NULL);
10646
}
10647
memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10648
ret->schema = schema;
10649
ret->error = xmlGenericError;
10650
ret->userData = xmlGenericErrorContext;
10651
ret->errNr = 0;
10652
ret->errMax = 0;
10653
ret->err = NULL;
10654
ret->errTab = NULL;
10655
if (schema != NULL)
10656
ret->idref = schema->idref;
10657
ret->states = NULL;
10658
ret->freeState = NULL;
10659
ret->freeStates = NULL;
10660
ret->errNo = XML_RELAXNG_OK;
10661
return (ret);
10662
}
10663
10664
/**
10665
* xmlRelaxNGFreeValidCtxt:
10666
* @ctxt: the schema validation context
10667
*
10668
* Free the resources associated to the schema validation context
10669
*/
10670
void
10671
xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10672
{
10673
int k;
10674
10675
if (ctxt == NULL)
10676
return;
10677
if (ctxt->states != NULL)
10678
xmlRelaxNGFreeStates(NULL, ctxt->states);
10679
if (ctxt->freeState != NULL) {
10680
for (k = 0; k < ctxt->freeState->nbState; k++) {
10681
xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10682
}
10683
xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10684
}
10685
if (ctxt->freeStates != NULL) {
10686
for (k = 0; k < ctxt->freeStatesNr; k++) {
10687
xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10688
}
10689
xmlFree(ctxt->freeStates);
10690
}
10691
if (ctxt->errTab != NULL)
10692
xmlFree(ctxt->errTab);
10693
if (ctxt->elemTab != NULL) {
10694
xmlRegExecCtxtPtr exec;
10695
10696
exec = xmlRelaxNGElemPop(ctxt);
10697
while (exec != NULL) {
10698
xmlRegFreeExecCtxt(exec);
10699
exec = xmlRelaxNGElemPop(ctxt);
10700
}
10701
xmlFree(ctxt->elemTab);
10702
}
10703
xmlFree(ctxt);
10704
}
10705
10706
/**
10707
* xmlRelaxNGSetValidErrors:
10708
* @ctxt: a Relax-NG validation context
10709
* @err: the error function
10710
* @warn: the warning function
10711
* @ctx: the functions context
10712
*
10713
* Set the error and warning callback information
10714
*/
10715
void
10716
xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10717
xmlRelaxNGValidityErrorFunc err,
10718
xmlRelaxNGValidityWarningFunc warn, void *ctx)
10719
{
10720
if (ctxt == NULL)
10721
return;
10722
ctxt->error = err;
10723
ctxt->warning = warn;
10724
ctxt->userData = ctx;
10725
ctxt->serror = NULL;
10726
}
10727
10728
/**
10729
* xmlRelaxNGSetValidStructuredErrors:
10730
* @ctxt: a Relax-NG validation context
10731
* @serror: the structured error function
10732
* @ctx: the functions context
10733
*
10734
* Set the structured error callback
10735
*/
10736
void
10737
xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
10738
xmlStructuredErrorFunc serror, void *ctx)
10739
{
10740
if (ctxt == NULL)
10741
return;
10742
ctxt->serror = serror;
10743
ctxt->error = NULL;
10744
ctxt->warning = NULL;
10745
ctxt->userData = ctx;
10746
}
10747
10748
/**
10749
* xmlRelaxNGGetValidErrors:
10750
* @ctxt: a Relax-NG validation context
10751
* @err: the error function result
10752
* @warn: the warning function result
10753
* @ctx: the functions context result
10754
*
10755
* Get the error and warning callback information
10756
*
10757
* Returns -1 in case of error and 0 otherwise
10758
*/
10759
int
10760
xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10761
xmlRelaxNGValidityErrorFunc * err,
10762
xmlRelaxNGValidityWarningFunc * warn, void **ctx)
10763
{
10764
if (ctxt == NULL)
10765
return (-1);
10766
if (err != NULL)
10767
*err = ctxt->error;
10768
if (warn != NULL)
10769
*warn = ctxt->warning;
10770
if (ctx != NULL)
10771
*ctx = ctxt->userData;
10772
return (0);
10773
}
10774
10775
/**
10776
* xmlRelaxNGValidateDoc:
10777
* @ctxt: a Relax-NG validation context
10778
* @doc: a parsed document tree
10779
*
10780
* Validate a document tree in memory.
10781
*
10782
* Returns 0 if the document is valid, a positive error code
10783
* number otherwise and -1 in case of internal or API error.
10784
*/
10785
int
10786
xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10787
{
10788
int ret;
10789
10790
if ((ctxt == NULL) || (doc == NULL))
10791
return (-1);
10792
10793
ctxt->doc = doc;
10794
10795
ret = xmlRelaxNGValidateDocument(ctxt, doc);
10796
/*
10797
* Remove all left PSVI
10798
*/
10799
xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
10800
10801
/*
10802
* TODO: build error codes
10803
*/
10804
if (ret == -1)
10805
return (1);
10806
return (ret);
10807
}
10808
10809
#endif /* LIBXML_SCHEMAS_ENABLED */
10810
10811