~ubuntu-branches/ubuntu/wily/opencollada/wily-proposed

« back to all changes in this revision

Viewing changes to Externals/LibXML/relaxng.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2015-05-14 17:23:27 UTC
  • Revision ID: package-import@ubuntu.com-20150514172327-f862u8envms01fra
Tags: upstream-0.1.0~20140703.ddf8f47+dfsg1
ImportĀ upstreamĀ versionĀ 0.1.0~20140703.ddf8f47+dfsg1

Show diffs side-by-side

added added

removed removed

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