Coverage Report

Created: 2023-11-19 06:13

/src/libxml2-2.11.5/relaxng.c
Line
Count
Source (jump to first uncovered line)
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 <stddef.h>
24
#include <libxml/xmlmemory.h>
25
#include <libxml/parser.h>
26
#include <libxml/parserInternals.h>
27
#include <libxml/hash.h>
28
#include <libxml/uri.h>
29
30
#include <libxml/relaxng.h>
31
32
#include <libxml/xmlschemastypes.h>
33
#include <libxml/xmlautomata.h>
34
#include <libxml/xmlregexp.h>
35
#include <libxml/xmlschemastypes.h>
36
37
#include "private/error.h"
38
#include "private/regexp.h"
39
#include "private/string.h"
40
41
/*
42
 * The Relax-NG namespace
43
 */
44
static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
45
    "http://relaxng.org/ns/structure/1.0";
46
47
#define IS_RELAXNG(node, typ)           \
48
0
   ((node != NULL) && (node->ns != NULL) &&       \
49
0
    (node->type == XML_ELEMENT_NODE) &&         \
50
0
    (xmlStrEqual(node->name, (const xmlChar *) typ)) &&   \
51
0
    (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
52
53
54
#if 0
55
#define DEBUG 1
56
57
#define DEBUG_GRAMMAR 1
58
59
#define DEBUG_CONTENT 1
60
61
#define DEBUG_TYPE 1
62
63
#define DEBUG_VALID 1
64
65
#define DEBUG_INTERLEAVE 1
66
67
#define DEBUG_LIST 1
68
69
#define DEBUG_INCLUDE 1
70
71
#define DEBUG_ERROR 1
72
73
#define DEBUG_COMPILE 1
74
75
#define DEBUG_PROGRESSIVE 1
76
#endif
77
78
0
#define MAX_ERROR 5
79
80
#define TODO                \
81
0
    xmlGenericError(xmlGenericErrorContext,       \
82
0
      "Unimplemented block at %s:%d\n",       \
83
0
            __FILE__, __LINE__);
84
85
typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
86
typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
87
88
typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
89
typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
90
91
typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
92
typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
93
94
typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
95
typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
96
97
typedef enum {
98
    XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */
99
    XML_RELAXNG_COMBINE_CHOICE, /* choice */
100
    XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */
101
} xmlRelaxNGCombine;
102
103
typedef enum {
104
    XML_RELAXNG_CONTENT_ERROR = -1,
105
    XML_RELAXNG_CONTENT_EMPTY = 0,
106
    XML_RELAXNG_CONTENT_SIMPLE,
107
    XML_RELAXNG_CONTENT_COMPLEX
108
} xmlRelaxNGContentType;
109
110
typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
111
typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
112
113
struct _xmlRelaxNGGrammar {
114
    xmlRelaxNGGrammarPtr parent;        /* the parent grammar if any */
115
    xmlRelaxNGGrammarPtr children;      /* the children grammar if any */
116
    xmlRelaxNGGrammarPtr next;  /* the next grammar if any */
117
    xmlRelaxNGDefinePtr start;  /* <start> content */
118
    xmlRelaxNGCombine combine;  /* the default combine value */
119
    xmlRelaxNGDefinePtr startList;      /* list of <start> definitions */
120
    xmlHashTablePtr defs;       /* define* */
121
    xmlHashTablePtr refs;       /* references */
122
};
123
124
125
typedef enum {
126
    XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */
127
    XML_RELAXNG_EMPTY = 0,      /* an empty pattern */
128
    XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
129
    XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */
130
    XML_RELAXNG_TEXT,           /* textual content */
131
    XML_RELAXNG_ELEMENT,        /* an element */
132
    XML_RELAXNG_DATATYPE,       /* external data type definition */
133
    XML_RELAXNG_PARAM,          /* external data type parameter */
134
    XML_RELAXNG_VALUE,          /* value from an external data type definition */
135
    XML_RELAXNG_LIST,           /* a list of patterns */
136
    XML_RELAXNG_ATTRIBUTE,      /* an attribute following a pattern */
137
    XML_RELAXNG_DEF,            /* a definition */
138
    XML_RELAXNG_REF,            /* reference to a definition */
139
    XML_RELAXNG_EXTERNALREF,    /* reference to an external def */
140
    XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */
141
    XML_RELAXNG_OPTIONAL,       /* optional patterns */
142
    XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */
143
    XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */
144
    XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */
145
    XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */
146
    XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */
147
    XML_RELAXNG_START           /* Used to keep track of starts on grammars */
148
} xmlRelaxNGType;
149
150
0
#define IS_NULLABLE   (1 << 0)
151
0
#define IS_NOT_NULLABLE   (1 << 1)
152
0
#define IS_INDETERMINIST  (1 << 2)
153
0
#define IS_MIXED    (1 << 3)
154
0
#define IS_TRIABLE    (1 << 4)
155
0
#define IS_PROCESSED    (1 << 5)
156
0
#define IS_COMPILABLE   (1 << 6)
157
0
#define IS_NOT_COMPILABLE (1 << 7)
158
0
#define IS_EXTERNAL_REF         (1 << 8)
159
160
struct _xmlRelaxNGDefine {
161
    xmlRelaxNGType type;        /* the type of definition */
162
    xmlNodePtr node;            /* the node in the source */
163
    xmlChar *name;              /* the element local name if present */
164
    xmlChar *ns;                /* the namespace local name if present */
165
    xmlChar *value;             /* value when available */
166
    void *data;                 /* data lib or specific pointer */
167
    xmlRelaxNGDefinePtr content;        /* the expected content */
168
    xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
169
    xmlRelaxNGDefinePtr next;   /* list within grouping sequences */
170
    xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */
171
    xmlRelaxNGDefinePtr nameClass;      /* the nameClass definition if any */
172
    xmlRelaxNGDefinePtr nextHash;       /* next define in defs/refs hash tables */
173
    short depth;                /* used for the cycle detection */
174
    short dflags;               /* define related flags */
175
    xmlRegexpPtr contModel;     /* a compiled content model if available */
176
};
177
178
/**
179
 * _xmlRelaxNG:
180
 *
181
 * A RelaxNGs definition
182
 */
183
struct _xmlRelaxNG {
184
    void *_private;             /* unused by the library for users or bindings */
185
    xmlRelaxNGGrammarPtr topgrammar;
186
    xmlDocPtr doc;
187
188
    int idref;                  /* requires idref checking */
189
190
    xmlHashTablePtr defs;       /* define */
191
    xmlHashTablePtr refs;       /* references */
192
    xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
193
    xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
194
    int defNr;                  /* number of defines used */
195
    xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
196
197
};
198
199
0
#define XML_RELAXNG_IN_ATTRIBUTE  (1 << 0)
200
0
#define XML_RELAXNG_IN_ONEORMORE  (1 << 1)
201
0
#define XML_RELAXNG_IN_LIST   (1 << 2)
202
0
#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
203
0
#define XML_RELAXNG_IN_START    (1 << 4)
204
0
#define XML_RELAXNG_IN_OOMGROUP   (1 << 5)
205
0
#define XML_RELAXNG_IN_OOMINTERLEAVE  (1 << 6)
206
0
#define XML_RELAXNG_IN_EXTERNALREF  (1 << 7)
207
0
#define XML_RELAXNG_IN_ANYEXCEPT  (1 << 8)
208
0
#define XML_RELAXNG_IN_NSEXCEPT   (1 << 9)
209
210
struct _xmlRelaxNGParserCtxt {
211
    void *userData;             /* user specific data block */
212
    xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
213
    xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
214
    xmlStructuredErrorFunc serror;
215
    xmlRelaxNGValidErr err;
216
217
    xmlRelaxNGPtr schema;       /* The schema in use */
218
    xmlRelaxNGGrammarPtr grammar;       /* the current grammar */
219
    xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
220
    int flags;                  /* parser flags */
221
    int nbErrors;               /* number of errors at parse time */
222
    int nbWarnings;             /* number of warnings at parse time */
223
    const xmlChar *define;      /* the current define scope */
224
    xmlRelaxNGDefinePtr def;    /* the current define */
225
226
    int nbInterleaves;
227
    xmlHashTablePtr interleaves;        /* keep track of all the interleaves */
228
229
    xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
230
    xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
231
    xmlChar *URL;
232
    xmlDocPtr document;
233
234
    int defNr;                  /* number of defines used */
235
    int defMax;                 /* number of defines allocated */
236
    xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
237
238
    const char *buffer;
239
    int size;
240
241
    /* the document stack */
242
    xmlRelaxNGDocumentPtr doc;  /* Current parsed external ref */
243
    int docNr;                  /* Depth of the parsing stack */
244
    int docMax;                 /* Max depth of the parsing stack */
245
    xmlRelaxNGDocumentPtr *docTab;      /* array of docs */
246
247
    /* the include stack */
248
    xmlRelaxNGIncludePtr inc;   /* Current parsed include */
249
    int incNr;                  /* Depth of the include parsing stack */
250
    int incMax;                 /* Max depth of the parsing stack */
251
    xmlRelaxNGIncludePtr *incTab;       /* array of incs */
252
253
    int idref;                  /* requires idref checking */
254
255
    /* used to compile content models */
256
    xmlAutomataPtr am;          /* the automata */
257
    xmlAutomataStatePtr state;  /* used to build the automata */
258
259
    int crng;     /* compact syntax and other flags */
260
    int freedoc;    /* need to free the document */
261
};
262
263
0
#define FLAGS_IGNORABLE   1
264
0
#define FLAGS_NEGATIVE    2
265
0
#define FLAGS_MIXED_CONTENT 4
266
0
#define FLAGS_NOERROR   8
267
268
/**
269
 * xmlRelaxNGInterleaveGroup:
270
 *
271
 * A RelaxNGs partition set associated to lists of definitions
272
 */
273
typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
274
typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
275
struct _xmlRelaxNGInterleaveGroup {
276
    xmlRelaxNGDefinePtr rule;   /* the rule to satisfy */
277
    xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */
278
    xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
279
};
280
281
0
#define IS_DETERMINIST    1
282
0
#define IS_NEEDCHECK    2
283
284
/**
285
 * xmlRelaxNGPartitions:
286
 *
287
 * A RelaxNGs partition associated to an interleave group
288
 */
289
typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
290
typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
291
struct _xmlRelaxNGPartition {
292
    int nbgroups;               /* number of groups in the partitions */
293
    xmlHashTablePtr triage;     /* hash table used to direct nodes to the
294
                                 * right group when possible */
295
    int flags;                  /* determinist ? */
296
    xmlRelaxNGInterleaveGroupPtr *groups;
297
};
298
299
/**
300
 * xmlRelaxNGValidState:
301
 *
302
 * A RelaxNGs validation state
303
 */
304
0
#define MAX_ATTR 20
305
typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
306
typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
307
struct _xmlRelaxNGValidState {
308
    xmlNodePtr node;            /* the current node */
309
    xmlNodePtr seq;             /* the sequence of children left to validate */
310
    int nbAttrs;                /* the number of attributes */
311
    int maxAttrs;               /* the size of attrs */
312
    int nbAttrLeft;             /* the number of attributes left to validate */
313
    xmlChar *value;             /* the value when operating on string */
314
    xmlChar *endvalue;          /* the end value when operating on string */
315
    xmlAttrPtr *attrs;          /* the array of attributes */
316
};
317
318
/**
319
 * xmlRelaxNGStates:
320
 *
321
 * A RelaxNGs container for validation state
322
 */
323
typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
324
typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
325
struct _xmlRelaxNGStates {
326
    int nbState;                /* the number of states */
327
    int maxState;               /* the size of the array */
328
    xmlRelaxNGValidStatePtr *tabState;
329
};
330
331
0
#define ERROR_IS_DUP  1
332
333
/**
334
 * xmlRelaxNGValidError:
335
 *
336
 * A RelaxNGs validation error
337
 */
338
typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
339
typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
340
struct _xmlRelaxNGValidError {
341
    xmlRelaxNGValidErr err;     /* the error number */
342
    int flags;                  /* flags */
343
    xmlNodePtr node;            /* the current node */
344
    xmlNodePtr seq;             /* the current child */
345
    const xmlChar *arg1;        /* first arg */
346
    const xmlChar *arg2;        /* second arg */
347
};
348
349
/**
350
 * xmlRelaxNGValidCtxt:
351
 *
352
 * A RelaxNGs validation context
353
 */
354
355
struct _xmlRelaxNGValidCtxt {
356
    void *userData;             /* user specific data block */
357
    xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
358
    xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
359
    xmlStructuredErrorFunc serror;
360
    int nbErrors;               /* number of errors in validation */
361
362
    xmlRelaxNGPtr schema;       /* The schema in use */
363
    xmlDocPtr doc;              /* the document being validated */
364
    int flags;                  /* validation flags */
365
    int depth;                  /* validation depth */
366
    int idref;                  /* requires idref checking */
367
    int errNo;                  /* the first error found */
368
369
    /*
370
     * Errors accumulated in branches may have to be stacked to be
371
     * provided back when it's sure they affect validation.
372
     */
373
    xmlRelaxNGValidErrorPtr err;        /* Last error */
374
    int errNr;                  /* Depth of the error stack */
375
    int errMax;                 /* Max depth of the error stack */
376
    xmlRelaxNGValidErrorPtr errTab;     /* stack of errors */
377
378
    xmlRelaxNGValidStatePtr state;      /* the current validation state */
379
    xmlRelaxNGStatesPtr states; /* the accumulated state list */
380
381
    xmlRelaxNGStatesPtr freeState;      /* the pool of free valid states */
382
    int freeStatesNr;
383
    int freeStatesMax;
384
    xmlRelaxNGStatesPtr *freeStates;    /* the pool of free state groups */
385
386
    /*
387
     * This is used for "progressive" validation
388
     */
389
    xmlRegExecCtxtPtr elem;     /* the current element regexp */
390
    int elemNr;                 /* the number of element validated */
391
    int elemMax;                /* the max depth of elements */
392
    xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
393
    int pstate;                 /* progressive state */
394
    xmlNodePtr pnode;           /* the current node */
395
    xmlRelaxNGDefinePtr pdef;   /* the non-streamable definition */
396
    int perr;                   /* signal error in content model
397
                                 * outside the regexp */
398
};
399
400
/**
401
 * xmlRelaxNGInclude:
402
 *
403
 * Structure associated to a RelaxNGs document element
404
 */
405
struct _xmlRelaxNGInclude {
406
    xmlRelaxNGIncludePtr next;  /* keep a chain of includes */
407
    xmlChar *href;              /* the normalized href value */
408
    xmlDocPtr doc;              /* the associated XML document */
409
    xmlRelaxNGDefinePtr content;        /* the definitions */
410
    xmlRelaxNGPtr schema;       /* the schema */
411
};
412
413
/**
414
 * xmlRelaxNGDocument:
415
 *
416
 * Structure associated to a RelaxNGs document element
417
 */
418
struct _xmlRelaxNGDocument {
419
    xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
420
    xmlChar *href;              /* the normalized href value */
421
    xmlDocPtr doc;              /* the associated XML document */
422
    xmlRelaxNGDefinePtr content;        /* the definitions */
423
    xmlRelaxNGPtr schema;       /* the schema */
424
    int externalRef;            /* 1 if an external ref */
425
};
426
427
428
/************************************************************************
429
 *                  *
430
 *    Some factorized error routines        *
431
 *                  *
432
 ************************************************************************/
433
434
/**
435
 * xmlRngPErrMemory:
436
 * @ctxt:  an Relax-NG parser context
437
 * @extra:  extra information
438
 *
439
 * Handle a redefinition of attribute error
440
 */
441
static void
442
xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
443
0
{
444
0
    xmlStructuredErrorFunc schannel = NULL;
445
0
    xmlGenericErrorFunc channel = NULL;
446
0
    void *data = NULL;
447
448
0
    if (ctxt != NULL) {
449
0
        if (ctxt->serror != NULL)
450
0
      schannel = ctxt->serror;
451
0
  else
452
0
      channel = ctxt->error;
453
0
        data = ctxt->userData;
454
0
        ctxt->nbErrors++;
455
0
    }
456
0
    if (extra)
457
0
        __xmlRaiseError(schannel, channel, data,
458
0
                        NULL, NULL, XML_FROM_RELAXNGP,
459
0
                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
460
0
                        NULL, NULL, 0, 0,
461
0
                        "Memory allocation failed : %s\n", extra);
462
0
    else
463
0
        __xmlRaiseError(schannel, channel, data,
464
0
                        NULL, NULL, XML_FROM_RELAXNGP,
465
0
                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
466
0
                        NULL, NULL, 0, 0, "Memory allocation failed\n");
467
0
}
468
469
/**
470
 * xmlRngVErrMemory:
471
 * @ctxt:  a Relax-NG validation context
472
 * @extra:  extra information
473
 *
474
 * Handle a redefinition of attribute error
475
 */
476
static void
477
xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
478
0
{
479
0
    xmlStructuredErrorFunc schannel = NULL;
480
0
    xmlGenericErrorFunc channel = NULL;
481
0
    void *data = NULL;
482
483
0
    if (ctxt != NULL) {
484
0
        if (ctxt->serror != NULL)
485
0
      schannel = ctxt->serror;
486
0
  else
487
0
      channel = ctxt->error;
488
0
        data = ctxt->userData;
489
0
        ctxt->nbErrors++;
490
0
    }
491
0
    if (extra)
492
0
        __xmlRaiseError(schannel, channel, data,
493
0
                        NULL, NULL, XML_FROM_RELAXNGV,
494
0
                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
495
0
                        NULL, NULL, 0, 0,
496
0
                        "Memory allocation failed : %s\n", extra);
497
0
    else
498
0
        __xmlRaiseError(schannel, channel, data,
499
0
                        NULL, NULL, XML_FROM_RELAXNGV,
500
0
                        XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
501
0
                        NULL, NULL, 0, 0, "Memory allocation failed\n");
502
0
}
503
504
/**
505
 * xmlRngPErr:
506
 * @ctxt:  a Relax-NG parser context
507
 * @node:  the node raising the error
508
 * @error:  the error code
509
 * @msg:  message
510
 * @str1:  extra info
511
 * @str2:  extra info
512
 *
513
 * Handle a Relax NG Parsing error
514
 */
515
static void LIBXML_ATTR_FORMAT(4,0)
516
xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
517
           const char *msg, const xmlChar * str1, const xmlChar * str2)
518
0
{
519
0
    xmlStructuredErrorFunc schannel = NULL;
520
0
    xmlGenericErrorFunc channel = NULL;
521
0
    void *data = NULL;
522
523
0
    if (ctxt != NULL) {
524
0
        if (ctxt->serror != NULL)
525
0
      schannel = ctxt->serror;
526
0
  else
527
0
      channel = ctxt->error;
528
0
        data = ctxt->userData;
529
0
        ctxt->nbErrors++;
530
0
    }
531
0
    __xmlRaiseError(schannel, channel, data,
532
0
                    NULL, node, XML_FROM_RELAXNGP,
533
0
                    error, XML_ERR_ERROR, NULL, 0,
534
0
                    (const char *) str1, (const char *) str2, NULL, 0, 0,
535
0
                    msg, str1, str2);
536
0
}
537
538
/**
539
 * xmlRngVErr:
540
 * @ctxt:  a Relax-NG validation context
541
 * @node:  the node raising the error
542
 * @error:  the error code
543
 * @msg:  message
544
 * @str1:  extra info
545
 * @str2:  extra info
546
 *
547
 * Handle a Relax NG Validation error
548
 */
549
static void LIBXML_ATTR_FORMAT(4,0)
550
xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
551
           const char *msg, const xmlChar * str1, const xmlChar * str2)
552
0
{
553
0
    xmlStructuredErrorFunc schannel = NULL;
554
0
    xmlGenericErrorFunc channel = NULL;
555
0
    void *data = NULL;
556
557
0
    if (ctxt != NULL) {
558
0
        if (ctxt->serror != NULL)
559
0
      schannel = ctxt->serror;
560
0
  else
561
0
      channel = ctxt->error;
562
0
        data = ctxt->userData;
563
0
        ctxt->nbErrors++;
564
0
    }
565
0
    __xmlRaiseError(schannel, channel, data,
566
0
                    NULL, node, XML_FROM_RELAXNGV,
567
0
                    error, XML_ERR_ERROR, NULL, 0,
568
0
                    (const char *) str1, (const char *) str2, NULL, 0, 0,
569
0
                    msg, str1, str2);
570
0
}
571
572
/************************************************************************
573
 *                  *
574
 *    Preliminary type checking interfaces      *
575
 *                  *
576
 ************************************************************************/
577
578
/**
579
 * xmlRelaxNGTypeHave:
580
 * @data:  data needed for the library
581
 * @type:  the type name
582
 * @value:  the value to check
583
 *
584
 * Function provided by a type library to check if a type is exported
585
 *
586
 * Returns 1 if yes, 0 if no and -1 in case of error.
587
 */
588
typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
589
590
/**
591
 * xmlRelaxNGTypeCheck:
592
 * @data:  data needed for the library
593
 * @type:  the type name
594
 * @value:  the value to check
595
 * @result:  place to store the result if needed
596
 *
597
 * Function provided by a type library to check if a value match a type
598
 *
599
 * Returns 1 if yes, 0 if no and -1 in case of error.
600
 */
601
typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
602
                                    const xmlChar * value, void **result,
603
                                    xmlNodePtr node);
604
605
/**
606
 * xmlRelaxNGFacetCheck:
607
 * @data:  data needed for the library
608
 * @type:  the type name
609
 * @facet:  the facet name
610
 * @val:  the facet value
611
 * @strval:  the string value
612
 * @value:  the value to check
613
 *
614
 * Function provided by a type library to check a value facet
615
 *
616
 * Returns 1 if yes, 0 if no and -1 in case of error.
617
 */
618
typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
619
                                     const xmlChar * facet,
620
                                     const xmlChar * val,
621
                                     const xmlChar * strval, void *value);
622
623
/**
624
 * xmlRelaxNGTypeFree:
625
 * @data:  data needed for the library
626
 * @result:  the value to free
627
 *
628
 * Function provided by a type library to free a returned result
629
 */
630
typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
631
632
/**
633
 * xmlRelaxNGTypeCompare:
634
 * @data:  data needed for the library
635
 * @type:  the type name
636
 * @value1:  the first value
637
 * @value2:  the second value
638
 *
639
 * Function provided by a type library to compare two values accordingly
640
 * to a type.
641
 *
642
 * Returns 1 if yes, 0 if no and -1 in case of error.
643
 */
644
typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
645
                                      const xmlChar * value1,
646
                                      xmlNodePtr ctxt1,
647
                                      void *comp1,
648
                                      const xmlChar * value2,
649
                                      xmlNodePtr ctxt2);
650
typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
651
typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
652
struct _xmlRelaxNGTypeLibrary {
653
    const xmlChar *namespace;   /* the datatypeLibrary value */
654
    void *data;                 /* data needed for the library */
655
    xmlRelaxNGTypeHave have;    /* the export function */
656
    xmlRelaxNGTypeCheck check;  /* the checking function */
657
    xmlRelaxNGTypeCompare comp; /* the compare function */
658
    xmlRelaxNGFacetCheck facet; /* the facet check function */
659
    xmlRelaxNGTypeFree freef;   /* the freeing function */
660
};
661
662
/************************************************************************
663
 *                  *
664
 *      Allocation functions        *
665
 *                  *
666
 ************************************************************************/
667
static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
668
static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
669
static void xmlRelaxNGNormExtSpace(xmlChar * value);
670
static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
671
static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
672
                                     ATTRIBUTE_UNUSED,
673
                                     xmlRelaxNGValidStatePtr state1,
674
                                     xmlRelaxNGValidStatePtr state2);
675
static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
676
                                     xmlRelaxNGValidStatePtr state);
677
678
/**
679
 * xmlRelaxNGFreeDocument:
680
 * @docu:  a document structure
681
 *
682
 * Deallocate a RelaxNG document structure.
683
 */
684
static void
685
xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
686
0
{
687
0
    if (docu == NULL)
688
0
        return;
689
690
0
    if (docu->href != NULL)
691
0
        xmlFree(docu->href);
692
0
    if (docu->doc != NULL)
693
0
        xmlFreeDoc(docu->doc);
694
0
    if (docu->schema != NULL)
695
0
        xmlRelaxNGFreeInnerSchema(docu->schema);
696
0
    xmlFree(docu);
697
0
}
698
699
/**
700
 * xmlRelaxNGFreeDocumentList:
701
 * @docu:  a list of  document structure
702
 *
703
 * Deallocate a RelaxNG document structures.
704
 */
705
static void
706
xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
707
0
{
708
0
    xmlRelaxNGDocumentPtr next;
709
710
0
    while (docu != NULL) {
711
0
        next = docu->next;
712
0
        xmlRelaxNGFreeDocument(docu);
713
0
        docu = next;
714
0
    }
715
0
}
716
717
/**
718
 * xmlRelaxNGFreeInclude:
719
 * @incl:  a include structure
720
 *
721
 * Deallocate a RelaxNG include structure.
722
 */
723
static void
724
xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
725
0
{
726
0
    if (incl == NULL)
727
0
        return;
728
729
0
    if (incl->href != NULL)
730
0
        xmlFree(incl->href);
731
0
    if (incl->doc != NULL)
732
0
        xmlFreeDoc(incl->doc);
733
0
    if (incl->schema != NULL)
734
0
        xmlRelaxNGFree(incl->schema);
735
0
    xmlFree(incl);
736
0
}
737
738
/**
739
 * xmlRelaxNGFreeIncludeList:
740
 * @incl:  a include structure list
741
 *
742
 * Deallocate a RelaxNG include structure.
743
 */
744
static void
745
xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
746
0
{
747
0
    xmlRelaxNGIncludePtr next;
748
749
0
    while (incl != NULL) {
750
0
        next = incl->next;
751
0
        xmlRelaxNGFreeInclude(incl);
752
0
        incl = next;
753
0
    }
754
0
}
755
756
/**
757
 * xmlRelaxNGNewRelaxNG:
758
 * @ctxt:  a Relax-NG validation context (optional)
759
 *
760
 * Allocate a new RelaxNG structure.
761
 *
762
 * Returns the newly allocated structure or NULL in case or error
763
 */
764
static xmlRelaxNGPtr
765
xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
766
0
{
767
0
    xmlRelaxNGPtr ret;
768
769
0
    ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
770
0
    if (ret == NULL) {
771
0
        xmlRngPErrMemory(ctxt, NULL);
772
0
        return (NULL);
773
0
    }
774
0
    memset(ret, 0, sizeof(xmlRelaxNG));
775
776
0
    return (ret);
777
0
}
778
779
/**
780
 * xmlRelaxNGFreeInnerSchema:
781
 * @schema:  a schema structure
782
 *
783
 * Deallocate a RelaxNG schema structure.
784
 */
785
static void
786
xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
787
0
{
788
0
    if (schema == NULL)
789
0
        return;
790
791
0
    if (schema->doc != NULL)
792
0
        xmlFreeDoc(schema->doc);
793
0
    if (schema->defTab != NULL) {
794
0
        int i;
795
796
0
        for (i = 0; i < schema->defNr; i++)
797
0
            xmlRelaxNGFreeDefine(schema->defTab[i]);
798
0
        xmlFree(schema->defTab);
799
0
    }
800
801
0
    xmlFree(schema);
802
0
}
803
804
/**
805
 * xmlRelaxNGFree:
806
 * @schema:  a schema structure
807
 *
808
 * Deallocate a RelaxNG structure.
809
 */
810
void
811
xmlRelaxNGFree(xmlRelaxNGPtr schema)
812
0
{
813
0
    if (schema == NULL)
814
0
        return;
815
816
0
    if (schema->topgrammar != NULL)
817
0
        xmlRelaxNGFreeGrammar(schema->topgrammar);
818
0
    if (schema->doc != NULL)
819
0
        xmlFreeDoc(schema->doc);
820
0
    if (schema->documents != NULL)
821
0
        xmlRelaxNGFreeDocumentList(schema->documents);
822
0
    if (schema->includes != NULL)
823
0
        xmlRelaxNGFreeIncludeList(schema->includes);
824
0
    if (schema->defTab != NULL) {
825
0
        int i;
826
827
0
        for (i = 0; i < schema->defNr; i++)
828
0
            xmlRelaxNGFreeDefine(schema->defTab[i]);
829
0
        xmlFree(schema->defTab);
830
0
    }
831
832
0
    xmlFree(schema);
833
0
}
834
835
/**
836
 * xmlRelaxNGNewGrammar:
837
 * @ctxt:  a Relax-NG validation context (optional)
838
 *
839
 * Allocate a new RelaxNG grammar.
840
 *
841
 * Returns the newly allocated structure or NULL in case or error
842
 */
843
static xmlRelaxNGGrammarPtr
844
xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
845
0
{
846
0
    xmlRelaxNGGrammarPtr ret;
847
848
0
    ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
849
0
    if (ret == NULL) {
850
0
        xmlRngPErrMemory(ctxt, NULL);
851
0
        return (NULL);
852
0
    }
853
0
    memset(ret, 0, sizeof(xmlRelaxNGGrammar));
854
855
0
    return (ret);
856
0
}
857
858
/**
859
 * xmlRelaxNGFreeGrammar:
860
 * @grammar:  a grammar structure
861
 *
862
 * Deallocate a RelaxNG grammar structure.
863
 */
864
static void
865
xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
866
0
{
867
0
    if (grammar == NULL)
868
0
        return;
869
870
0
    if (grammar->children != NULL) {
871
0
        xmlRelaxNGFreeGrammar(grammar->children);
872
0
    }
873
0
    if (grammar->next != NULL) {
874
0
        xmlRelaxNGFreeGrammar(grammar->next);
875
0
    }
876
0
    if (grammar->refs != NULL) {
877
0
        xmlHashFree(grammar->refs, NULL);
878
0
    }
879
0
    if (grammar->defs != NULL) {
880
0
        xmlHashFree(grammar->defs, NULL);
881
0
    }
882
883
0
    xmlFree(grammar);
884
0
}
885
886
/**
887
 * xmlRelaxNGNewDefine:
888
 * @ctxt:  a Relax-NG validation context
889
 * @node:  the node in the input document.
890
 *
891
 * Allocate a new RelaxNG define.
892
 *
893
 * Returns the newly allocated structure or NULL in case or error
894
 */
895
static xmlRelaxNGDefinePtr
896
xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
897
0
{
898
0
    xmlRelaxNGDefinePtr ret;
899
900
0
    if (ctxt->defMax == 0) {
901
0
        ctxt->defMax = 16;
902
0
        ctxt->defNr = 0;
903
0
        ctxt->defTab = (xmlRelaxNGDefinePtr *)
904
0
            xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
905
0
        if (ctxt->defTab == NULL) {
906
0
            xmlRngPErrMemory(ctxt, "allocating define\n");
907
0
            return (NULL);
908
0
        }
909
0
    } else if (ctxt->defMax <= ctxt->defNr) {
910
0
        xmlRelaxNGDefinePtr *tmp;
911
912
0
        ctxt->defMax *= 2;
913
0
        tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
914
0
                                                 ctxt->defMax *
915
0
                                                 sizeof
916
0
                                                 (xmlRelaxNGDefinePtr));
917
0
        if (tmp == NULL) {
918
0
            xmlRngPErrMemory(ctxt, "allocating define\n");
919
0
            return (NULL);
920
0
        }
921
0
        ctxt->defTab = tmp;
922
0
    }
923
0
    ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
924
0
    if (ret == NULL) {
925
0
        xmlRngPErrMemory(ctxt, "allocating define\n");
926
0
        return (NULL);
927
0
    }
928
0
    memset(ret, 0, sizeof(xmlRelaxNGDefine));
929
0
    ctxt->defTab[ctxt->defNr++] = ret;
930
0
    ret->node = node;
931
0
    ret->depth = -1;
932
0
    return (ret);
933
0
}
934
935
/**
936
 * xmlRelaxNGFreePartition:
937
 * @partitions:  a partition set structure
938
 *
939
 * Deallocate RelaxNG partition set structures.
940
 */
941
static void
942
xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
943
0
{
944
0
    xmlRelaxNGInterleaveGroupPtr group;
945
0
    int j;
946
947
0
    if (partitions != NULL) {
948
0
        if (partitions->groups != NULL) {
949
0
            for (j = 0; j < partitions->nbgroups; j++) {
950
0
                group = partitions->groups[j];
951
0
                if (group != NULL) {
952
0
                    if (group->defs != NULL)
953
0
                        xmlFree(group->defs);
954
0
                    if (group->attrs != NULL)
955
0
                        xmlFree(group->attrs);
956
0
                    xmlFree(group);
957
0
                }
958
0
            }
959
0
            xmlFree(partitions->groups);
960
0
        }
961
0
        if (partitions->triage != NULL) {
962
0
            xmlHashFree(partitions->triage, NULL);
963
0
        }
964
0
        xmlFree(partitions);
965
0
    }
966
0
}
967
968
/**
969
 * xmlRelaxNGFreeDefine:
970
 * @define:  a define structure
971
 *
972
 * Deallocate a RelaxNG define structure.
973
 */
974
static void
975
xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
976
0
{
977
0
    if (define == NULL)
978
0
        return;
979
980
0
    if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
981
0
        xmlRelaxNGTypeLibraryPtr lib;
982
983
0
        lib = (xmlRelaxNGTypeLibraryPtr) define->data;
984
0
        if ((lib != NULL) && (lib->freef != NULL))
985
0
            lib->freef(lib->data, (void *) define->attrs);
986
0
    }
987
0
    if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
988
0
        xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
989
0
    if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
990
0
        xmlHashFree((xmlHashTablePtr) define->data, NULL);
991
0
    if (define->name != NULL)
992
0
        xmlFree(define->name);
993
0
    if (define->ns != NULL)
994
0
        xmlFree(define->ns);
995
0
    if (define->value != NULL)
996
0
        xmlFree(define->value);
997
0
    if (define->contModel != NULL)
998
0
        xmlRegFreeRegexp(define->contModel);
999
0
    xmlFree(define);
1000
0
}
1001
1002
/**
1003
 * xmlRelaxNGNewStates:
1004
 * @ctxt:  a Relax-NG validation context
1005
 * @size:  the default size for the container
1006
 *
1007
 * Allocate a new RelaxNG validation state container
1008
 *
1009
 * Returns the newly allocated structure or NULL in case or error
1010
 */
1011
static xmlRelaxNGStatesPtr
1012
xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
1013
0
{
1014
0
    xmlRelaxNGStatesPtr ret;
1015
1016
0
    if ((ctxt != NULL) &&
1017
0
        (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
1018
0
        ctxt->freeStatesNr--;
1019
0
        ret = ctxt->freeStates[ctxt->freeStatesNr];
1020
0
        ret->nbState = 0;
1021
0
        return (ret);
1022
0
    }
1023
0
    if (size < 16)
1024
0
        size = 16;
1025
1026
0
    ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
1027
0
                                          (size -
1028
0
                                           1) *
1029
0
                                          sizeof(xmlRelaxNGValidStatePtr));
1030
0
    if (ret == NULL) {
1031
0
        xmlRngVErrMemory(ctxt, "allocating states\n");
1032
0
        return (NULL);
1033
0
    }
1034
0
    ret->nbState = 0;
1035
0
    ret->maxState = size;
1036
0
    ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
1037
0
                                                          sizeof
1038
0
                                                          (xmlRelaxNGValidStatePtr));
1039
0
    if (ret->tabState == NULL) {
1040
0
        xmlRngVErrMemory(ctxt, "allocating states\n");
1041
0
        xmlFree(ret);
1042
0
        return (NULL);
1043
0
    }
1044
0
    return (ret);
1045
0
}
1046
1047
/**
1048
 * xmlRelaxNGAddStateUniq:
1049
 * @ctxt:  a Relax-NG validation context
1050
 * @states:  the states container
1051
 * @state:  the validation state
1052
 *
1053
 * Add a RelaxNG validation state to the container without checking
1054
 * for unicity.
1055
 *
1056
 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1057
 */
1058
static int
1059
xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
1060
                        xmlRelaxNGStatesPtr states,
1061
                        xmlRelaxNGValidStatePtr state)
1062
0
{
1063
0
    if (state == NULL) {
1064
0
        return (-1);
1065
0
    }
1066
0
    if (states->nbState >= states->maxState) {
1067
0
        xmlRelaxNGValidStatePtr *tmp;
1068
0
        int size;
1069
1070
0
        size = states->maxState * 2;
1071
0
        tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1072
0
                                                     (size) *
1073
0
                                                     sizeof
1074
0
                                                     (xmlRelaxNGValidStatePtr));
1075
0
        if (tmp == NULL) {
1076
0
            xmlRngVErrMemory(ctxt, "adding states\n");
1077
0
            return (-1);
1078
0
        }
1079
0
        states->tabState = tmp;
1080
0
        states->maxState = size;
1081
0
    }
1082
0
    states->tabState[states->nbState++] = state;
1083
0
    return (1);
1084
0
}
1085
1086
/**
1087
 * xmlRelaxNGAddState:
1088
 * @ctxt:  a Relax-NG validation context
1089
 * @states:  the states container
1090
 * @state:  the validation state
1091
 *
1092
 * Add a RelaxNG validation state to the container
1093
 *
1094
 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1095
 */
1096
static int
1097
xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
1098
                    xmlRelaxNGStatesPtr states,
1099
                    xmlRelaxNGValidStatePtr state)
1100
0
{
1101
0
    int i;
1102
1103
0
    if (state == NULL || states == NULL) {
1104
0
        return (-1);
1105
0
    }
1106
0
    if (states->nbState >= states->maxState) {
1107
0
        xmlRelaxNGValidStatePtr *tmp;
1108
0
        int size;
1109
1110
0
        size = states->maxState * 2;
1111
0
        tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
1112
0
                                                     (size) *
1113
0
                                                     sizeof
1114
0
                                                     (xmlRelaxNGValidStatePtr));
1115
0
        if (tmp == NULL) {
1116
0
            xmlRngVErrMemory(ctxt, "adding states\n");
1117
0
            return (-1);
1118
0
        }
1119
0
        states->tabState = tmp;
1120
0
        states->maxState = size;
1121
0
    }
1122
0
    for (i = 0; i < states->nbState; i++) {
1123
0
        if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
1124
0
            xmlRelaxNGFreeValidState(ctxt, state);
1125
0
            return (0);
1126
0
        }
1127
0
    }
1128
0
    states->tabState[states->nbState++] = state;
1129
0
    return (1);
1130
0
}
1131
1132
/**
1133
 * xmlRelaxNGFreeStates:
1134
 * @ctxt:  a Relax-NG validation context
1135
 * @states:  the container
1136
 *
1137
 * Free a RelaxNG validation state container
1138
 */
1139
static void
1140
xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
1141
                     xmlRelaxNGStatesPtr states)
1142
0
{
1143
0
    if (states == NULL)
1144
0
        return;
1145
0
    if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
1146
0
        ctxt->freeStatesMax = 40;
1147
0
        ctxt->freeStatesNr = 0;
1148
0
        ctxt->freeStates = (xmlRelaxNGStatesPtr *)
1149
0
            xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
1150
0
        if (ctxt->freeStates == NULL) {
1151
0
            xmlRngVErrMemory(ctxt, "storing states\n");
1152
0
        }
1153
0
    } else if ((ctxt != NULL)
1154
0
               && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
1155
0
        xmlRelaxNGStatesPtr *tmp;
1156
1157
0
        tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
1158
0
                                                 2 * ctxt->freeStatesMax *
1159
0
                                                 sizeof
1160
0
                                                 (xmlRelaxNGStatesPtr));
1161
0
        if (tmp == NULL) {
1162
0
            xmlRngVErrMemory(ctxt, "storing states\n");
1163
0
            xmlFree(states->tabState);
1164
0
            xmlFree(states);
1165
0
            return;
1166
0
        }
1167
0
        ctxt->freeStates = tmp;
1168
0
        ctxt->freeStatesMax *= 2;
1169
0
    }
1170
0
    if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
1171
0
        xmlFree(states->tabState);
1172
0
        xmlFree(states);
1173
0
    } else {
1174
0
        ctxt->freeStates[ctxt->freeStatesNr++] = states;
1175
0
    }
1176
0
}
1177
1178
/**
1179
 * xmlRelaxNGNewValidState:
1180
 * @ctxt:  a Relax-NG validation context
1181
 * @node:  the current node or NULL for the document
1182
 *
1183
 * Allocate a new RelaxNG validation state
1184
 *
1185
 * Returns the newly allocated structure or NULL in case or error
1186
 */
1187
static xmlRelaxNGValidStatePtr
1188
xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1189
0
{
1190
0
    xmlRelaxNGValidStatePtr ret;
1191
0
    xmlAttrPtr attr;
1192
0
    xmlAttrPtr attrs[MAX_ATTR];
1193
0
    int nbAttrs = 0;
1194
0
    xmlNodePtr root = NULL;
1195
1196
0
    if (node == NULL) {
1197
0
        root = xmlDocGetRootElement(ctxt->doc);
1198
0
        if (root == NULL)
1199
0
            return (NULL);
1200
0
    } else {
1201
0
        attr = node->properties;
1202
0
        while (attr != NULL) {
1203
0
            if (nbAttrs < MAX_ATTR)
1204
0
                attrs[nbAttrs++] = attr;
1205
0
            else
1206
0
                nbAttrs++;
1207
0
            attr = attr->next;
1208
0
        }
1209
0
    }
1210
0
    if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1211
0
        ctxt->freeState->nbState--;
1212
0
        ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1213
0
    } else {
1214
0
        ret =
1215
0
            (xmlRelaxNGValidStatePtr)
1216
0
            xmlMalloc(sizeof(xmlRelaxNGValidState));
1217
0
        if (ret == NULL) {
1218
0
            xmlRngVErrMemory(ctxt, "allocating states\n");
1219
0
            return (NULL);
1220
0
        }
1221
0
        memset(ret, 0, sizeof(xmlRelaxNGValidState));
1222
0
    }
1223
0
    ret->value = NULL;
1224
0
    ret->endvalue = NULL;
1225
0
    if (node == NULL) {
1226
0
        ret->node = (xmlNodePtr) ctxt->doc;
1227
0
        ret->seq = root;
1228
0
    } else {
1229
0
        ret->node = node;
1230
0
        ret->seq = node->children;
1231
0
    }
1232
0
    ret->nbAttrs = 0;
1233
0
    if (nbAttrs > 0) {
1234
0
        if (ret->attrs == NULL) {
1235
0
            if (nbAttrs < 4)
1236
0
                ret->maxAttrs = 4;
1237
0
            else
1238
0
                ret->maxAttrs = nbAttrs;
1239
0
            ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1240
0
                                                  sizeof(xmlAttrPtr));
1241
0
            if (ret->attrs == NULL) {
1242
0
                xmlRngVErrMemory(ctxt, "allocating states\n");
1243
0
                return (ret);
1244
0
            }
1245
0
        } else if (ret->maxAttrs < nbAttrs) {
1246
0
            xmlAttrPtr *tmp;
1247
1248
0
            tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1249
0
                                            sizeof(xmlAttrPtr));
1250
0
            if (tmp == NULL) {
1251
0
                xmlRngVErrMemory(ctxt, "allocating states\n");
1252
0
                return (ret);
1253
0
            }
1254
0
            ret->attrs = tmp;
1255
0
            ret->maxAttrs = nbAttrs;
1256
0
        }
1257
0
        ret->nbAttrs = nbAttrs;
1258
0
        if (nbAttrs < MAX_ATTR) {
1259
0
            memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1260
0
        } else {
1261
0
            attr = node->properties;
1262
0
            nbAttrs = 0;
1263
0
            while (attr != NULL) {
1264
0
                ret->attrs[nbAttrs++] = attr;
1265
0
                attr = attr->next;
1266
0
            }
1267
0
        }
1268
0
    }
1269
0
    ret->nbAttrLeft = ret->nbAttrs;
1270
0
    return (ret);
1271
0
}
1272
1273
/**
1274
 * xmlRelaxNGCopyValidState:
1275
 * @ctxt:  a Relax-NG validation context
1276
 * @state:  a validation state
1277
 *
1278
 * Copy the validation state
1279
 *
1280
 * Returns the newly allocated structure or NULL in case or error
1281
 */
1282
static xmlRelaxNGValidStatePtr
1283
xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1284
                         xmlRelaxNGValidStatePtr state)
1285
0
{
1286
0
    xmlRelaxNGValidStatePtr ret;
1287
0
    unsigned int maxAttrs;
1288
0
    xmlAttrPtr *attrs;
1289
1290
0
    if (state == NULL)
1291
0
        return (NULL);
1292
0
    if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
1293
0
        ctxt->freeState->nbState--;
1294
0
        ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1295
0
    } else {
1296
0
        ret =
1297
0
            (xmlRelaxNGValidStatePtr)
1298
0
            xmlMalloc(sizeof(xmlRelaxNGValidState));
1299
0
        if (ret == NULL) {
1300
0
            xmlRngVErrMemory(ctxt, "allocating states\n");
1301
0
            return (NULL);
1302
0
        }
1303
0
        memset(ret, 0, sizeof(xmlRelaxNGValidState));
1304
0
    }
1305
0
    attrs = ret->attrs;
1306
0
    maxAttrs = ret->maxAttrs;
1307
0
    memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1308
0
    ret->attrs = attrs;
1309
0
    ret->maxAttrs = maxAttrs;
1310
0
    if (state->nbAttrs > 0) {
1311
0
        if (ret->attrs == NULL) {
1312
0
            ret->maxAttrs = state->maxAttrs;
1313
0
            ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1314
0
                                                  sizeof(xmlAttrPtr));
1315
0
            if (ret->attrs == NULL) {
1316
0
                xmlRngVErrMemory(ctxt, "allocating states\n");
1317
0
                ret->nbAttrs = 0;
1318
0
                return (ret);
1319
0
            }
1320
0
        } else if (ret->maxAttrs < state->nbAttrs) {
1321
0
            xmlAttrPtr *tmp;
1322
1323
0
            tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1324
0
                                            sizeof(xmlAttrPtr));
1325
0
            if (tmp == NULL) {
1326
0
                xmlRngVErrMemory(ctxt, "allocating states\n");
1327
0
                ret->nbAttrs = 0;
1328
0
                return (ret);
1329
0
            }
1330
0
            ret->maxAttrs = state->maxAttrs;
1331
0
            ret->attrs = tmp;
1332
0
        }
1333
0
        memcpy(ret->attrs, state->attrs,
1334
0
               state->nbAttrs * sizeof(xmlAttrPtr));
1335
0
    }
1336
0
    return (ret);
1337
0
}
1338
1339
/**
1340
 * xmlRelaxNGEqualValidState:
1341
 * @ctxt:  a Relax-NG validation context
1342
 * @state1:  a validation state
1343
 * @state2:  a validation state
1344
 *
1345
 * Compare the validation states for equality
1346
 *
1347
 * Returns 1 if equal, 0 otherwise
1348
 */
1349
static int
1350
xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1351
                          xmlRelaxNGValidStatePtr state1,
1352
                          xmlRelaxNGValidStatePtr state2)
1353
0
{
1354
0
    int i;
1355
1356
0
    if ((state1 == NULL) || (state2 == NULL))
1357
0
        return (0);
1358
0
    if (state1 == state2)
1359
0
        return (1);
1360
0
    if (state1->node != state2->node)
1361
0
        return (0);
1362
0
    if (state1->seq != state2->seq)
1363
0
        return (0);
1364
0
    if (state1->nbAttrLeft != state2->nbAttrLeft)
1365
0
        return (0);
1366
0
    if (state1->nbAttrs != state2->nbAttrs)
1367
0
        return (0);
1368
0
    if (state1->endvalue != state2->endvalue)
1369
0
        return (0);
1370
0
    if ((state1->value != state2->value) &&
1371
0
        (!xmlStrEqual(state1->value, state2->value)))
1372
0
        return (0);
1373
0
    for (i = 0; i < state1->nbAttrs; i++) {
1374
0
        if (state1->attrs[i] != state2->attrs[i])
1375
0
            return (0);
1376
0
    }
1377
0
    return (1);
1378
0
}
1379
1380
/**
1381
 * xmlRelaxNGFreeValidState:
1382
 * @state:  a validation state structure
1383
 *
1384
 * Deallocate a RelaxNG validation state structure.
1385
 */
1386
static void
1387
xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1388
                         xmlRelaxNGValidStatePtr state)
1389
0
{
1390
0
    if (state == NULL)
1391
0
        return;
1392
1393
0
    if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1394
0
        ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1395
0
    }
1396
0
    if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1397
0
        if (state->attrs != NULL)
1398
0
            xmlFree(state->attrs);
1399
0
        xmlFree(state);
1400
0
    } else {
1401
0
        xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1402
0
    }
1403
0
}
1404
1405
/************************************************************************
1406
 *                  *
1407
 *      Semi internal functions       *
1408
 *                  *
1409
 ************************************************************************/
1410
1411
/**
1412
 * xmlRelaxParserSetFlag:
1413
 * @ctxt: a RelaxNG parser context
1414
 * @flags: a set of flags values
1415
 *
1416
 * Semi private function used to pass information to a parser context
1417
 * which are a combination of xmlRelaxNGParserFlag .
1418
 *
1419
 * Returns 0 if success and -1 in case of error
1420
 */
1421
int
1422
xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
1423
0
{
1424
0
    if (ctxt == NULL) return(-1);
1425
0
    if (flags & XML_RELAXNGP_FREE_DOC) {
1426
0
        ctxt->crng |= XML_RELAXNGP_FREE_DOC;
1427
0
  flags -= XML_RELAXNGP_FREE_DOC;
1428
0
    }
1429
0
    if (flags & XML_RELAXNGP_CRNG) {
1430
0
        ctxt->crng |= XML_RELAXNGP_CRNG;
1431
0
  flags -= XML_RELAXNGP_CRNG;
1432
0
    }
1433
0
    if (flags != 0) return(-1);
1434
0
    return(0);
1435
0
}
1436
1437
/************************************************************************
1438
 *                  *
1439
 *      Document functions        *
1440
 *                  *
1441
 ************************************************************************/
1442
static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1443
                                      xmlDocPtr doc);
1444
1445
/**
1446
 * xmlRelaxNGIncludePush:
1447
 * @ctxt:  the parser context
1448
 * @value:  the element doc
1449
 *
1450
 * Pushes a new include on top of the include stack
1451
 *
1452
 * Returns 0 in case of error, the index in the stack otherwise
1453
 */
1454
static int
1455
xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1456
                      xmlRelaxNGIncludePtr value)
1457
0
{
1458
0
    if (ctxt->incTab == NULL) {
1459
0
        ctxt->incMax = 4;
1460
0
        ctxt->incNr = 0;
1461
0
        ctxt->incTab =
1462
0
            (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
1463
0
                                               sizeof(ctxt->incTab[0]));
1464
0
        if (ctxt->incTab == NULL) {
1465
0
            xmlRngPErrMemory(ctxt, "allocating include\n");
1466
0
            return (0);
1467
0
        }
1468
0
    }
1469
0
    if (ctxt->incNr >= ctxt->incMax) {
1470
0
        ctxt->incMax *= 2;
1471
0
        ctxt->incTab =
1472
0
            (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1473
0
                                                ctxt->incMax *
1474
0
                                                sizeof(ctxt->incTab[0]));
1475
0
        if (ctxt->incTab == NULL) {
1476
0
            xmlRngPErrMemory(ctxt, "allocating include\n");
1477
0
            return (0);
1478
0
        }
1479
0
    }
1480
0
    ctxt->incTab[ctxt->incNr] = value;
1481
0
    ctxt->inc = value;
1482
0
    return (ctxt->incNr++);
1483
0
}
1484
1485
/**
1486
 * xmlRelaxNGIncludePop:
1487
 * @ctxt: the parser context
1488
 *
1489
 * Pops the top include from the include stack
1490
 *
1491
 * Returns the include just removed
1492
 */
1493
static xmlRelaxNGIncludePtr
1494
xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1495
0
{
1496
0
    xmlRelaxNGIncludePtr ret;
1497
1498
0
    if (ctxt->incNr <= 0)
1499
0
        return (NULL);
1500
0
    ctxt->incNr--;
1501
0
    if (ctxt->incNr > 0)
1502
0
        ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1503
0
    else
1504
0
        ctxt->inc = NULL;
1505
0
    ret = ctxt->incTab[ctxt->incNr];
1506
0
    ctxt->incTab[ctxt->incNr] = NULL;
1507
0
    return (ret);
1508
0
}
1509
1510
/**
1511
 * xmlRelaxNGRemoveRedefine:
1512
 * @ctxt: the parser context
1513
 * @URL:  the normalized URL
1514
 * @target:  the included target
1515
 * @name:  the define name to eliminate
1516
 *
1517
 * Applies the elimination algorithm of 4.7
1518
 *
1519
 * Returns 0 in case of error, 1 in case of success.
1520
 */
1521
static int
1522
xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1523
                         const xmlChar * URL ATTRIBUTE_UNUSED,
1524
                         xmlNodePtr target, const xmlChar * name)
1525
0
{
1526
0
    int found = 0;
1527
0
    xmlNodePtr tmp, tmp2;
1528
0
    xmlChar *name2;
1529
1530
#ifdef DEBUG_INCLUDE
1531
    if (name == NULL)
1532
        xmlGenericError(xmlGenericErrorContext,
1533
                        "Elimination of <include> start from %s\n", URL);
1534
    else
1535
        xmlGenericError(xmlGenericErrorContext,
1536
                        "Elimination of <include> define %s from %s\n",
1537
                        name, URL);
1538
#endif
1539
0
    tmp = target;
1540
0
    while (tmp != NULL) {
1541
0
        tmp2 = tmp->next;
1542
0
        if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1543
0
            found = 1;
1544
0
            xmlUnlinkNode(tmp);
1545
0
            xmlFreeNode(tmp);
1546
0
        } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1547
0
            name2 = xmlGetProp(tmp, BAD_CAST "name");
1548
0
            xmlRelaxNGNormExtSpace(name2);
1549
0
            if (name2 != NULL) {
1550
0
                if (xmlStrEqual(name, name2)) {
1551
0
                    found = 1;
1552
0
                    xmlUnlinkNode(tmp);
1553
0
                    xmlFreeNode(tmp);
1554
0
                }
1555
0
                xmlFree(name2);
1556
0
            }
1557
0
        } else if (IS_RELAXNG(tmp, "include")) {
1558
0
            xmlChar *href = NULL;
1559
0
            xmlRelaxNGDocumentPtr inc = tmp->psvi;
1560
1561
0
            if ((inc != NULL) && (inc->doc != NULL) &&
1562
0
                (inc->doc->children != NULL)) {
1563
1564
0
                if (xmlStrEqual
1565
0
                    (inc->doc->children->name, BAD_CAST "grammar")) {
1566
#ifdef DEBUG_INCLUDE
1567
                    href = xmlGetProp(tmp, BAD_CAST "href");
1568
#endif
1569
0
                    if (xmlRelaxNGRemoveRedefine(ctxt, href,
1570
0
                                                 xmlDocGetRootElement(inc->doc)->children,
1571
0
                                                 name) == 1) {
1572
0
                        found = 1;
1573
0
                    }
1574
#ifdef DEBUG_INCLUDE
1575
                    if (href != NULL)
1576
                        xmlFree(href);
1577
#endif
1578
0
                }
1579
0
            }
1580
0
            if (xmlRelaxNGRemoveRedefine(ctxt, URL, tmp->children, name) == 1) {
1581
0
                found = 1;
1582
0
            }
1583
0
        }
1584
0
        tmp = tmp2;
1585
0
    }
1586
0
    return (found);
1587
0
}
1588
1589
/**
1590
 * xmlRelaxNGLoadInclude:
1591
 * @ctxt: the parser context
1592
 * @URL:  the normalized URL
1593
 * @node: the include node.
1594
 * @ns:  the namespace passed from the context.
1595
 *
1596
 * First lookup if the document is already loaded into the parser context,
1597
 * check against recursion. If not found the resource is loaded and
1598
 * the content is preprocessed before being returned back to the caller.
1599
 *
1600
 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1601
 */
1602
static xmlRelaxNGIncludePtr
1603
xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
1604
                      xmlNodePtr node, const xmlChar * ns)
1605
0
{
1606
0
    xmlRelaxNGIncludePtr ret = NULL;
1607
0
    xmlDocPtr doc;
1608
0
    int i;
1609
0
    xmlNodePtr root, cur;
1610
1611
#ifdef DEBUG_INCLUDE
1612
    xmlGenericError(xmlGenericErrorContext,
1613
                    "xmlRelaxNGLoadInclude(%s)\n", URL);
1614
#endif
1615
1616
    /*
1617
     * check against recursion in the stack
1618
     */
1619
0
    for (i = 0; i < ctxt->incNr; i++) {
1620
0
        if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1621
0
            xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
1622
0
                       "Detected an Include recursion for %s\n", URL,
1623
0
                       NULL);
1624
0
            return (NULL);
1625
0
        }
1626
0
    }
1627
1628
    /*
1629
     * load the document
1630
     */
1631
0
    doc = xmlReadFile((const char *) URL,NULL,0);
1632
0
    if (doc == NULL) {
1633
0
        xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
1634
0
                   "xmlRelaxNG: could not load %s\n", URL, NULL);
1635
0
        return (NULL);
1636
0
    }
1637
#ifdef DEBUG_INCLUDE
1638
    xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
1639
#endif
1640
1641
    /*
1642
     * Allocate the document structures and register it first.
1643
     */
1644
0
    ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1645
0
    if (ret == NULL) {
1646
0
        xmlRngPErrMemory(ctxt, "allocating include\n");
1647
0
        xmlFreeDoc(doc);
1648
0
        return (NULL);
1649
0
    }
1650
0
    memset(ret, 0, sizeof(xmlRelaxNGInclude));
1651
0
    ret->doc = doc;
1652
0
    ret->href = xmlStrdup(URL);
1653
0
    ret->next = ctxt->includes;
1654
0
    ctxt->includes = ret;
1655
1656
    /*
1657
     * transmit the ns if needed
1658
     */
1659
0
    if (ns != NULL) {
1660
0
        root = xmlDocGetRootElement(doc);
1661
0
        if (root != NULL) {
1662
0
            if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
1663
0
                xmlSetProp(root, BAD_CAST "ns", ns);
1664
0
            }
1665
0
        }
1666
0
    }
1667
1668
    /*
1669
     * push it on the stack
1670
     */
1671
0
    xmlRelaxNGIncludePush(ctxt, ret);
1672
1673
    /*
1674
     * Some preprocessing of the document content, this include recursing
1675
     * in the include stack.
1676
     */
1677
#ifdef DEBUG_INCLUDE
1678
    xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
1679
#endif
1680
1681
0
    doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1682
0
    if (doc == NULL) {
1683
0
        ctxt->inc = NULL;
1684
0
        return (NULL);
1685
0
    }
1686
1687
    /*
1688
     * Pop up the include from the stack
1689
     */
1690
0
    xmlRelaxNGIncludePop(ctxt);
1691
1692
#ifdef DEBUG_INCLUDE
1693
    xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
1694
#endif
1695
    /*
1696
     * Check that the top element is a grammar
1697
     */
1698
0
    root = xmlDocGetRootElement(doc);
1699
0
    if (root == NULL) {
1700
0
        xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
1701
0
                   "xmlRelaxNG: included document is empty %s\n", URL,
1702
0
                   NULL);
1703
0
        return (NULL);
1704
0
    }
1705
0
    if (!IS_RELAXNG(root, "grammar")) {
1706
0
        xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
1707
0
                   "xmlRelaxNG: included document %s root is not a grammar\n",
1708
0
                   URL, NULL);
1709
0
        return (NULL);
1710
0
    }
1711
1712
    /*
1713
     * Elimination of redefined rules in the include.
1714
     */
1715
0
    cur = node->children;
1716
0
    while (cur != NULL) {
1717
0
        if (IS_RELAXNG(cur, "start")) {
1718
0
            int found = 0;
1719
1720
0
            found =
1721
0
                xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
1722
0
            if (!found) {
1723
0
                xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
1724
0
                           "xmlRelaxNG: include %s has a start but not the included grammar\n",
1725
0
                           URL, NULL);
1726
0
            }
1727
0
        } else if (IS_RELAXNG(cur, "define")) {
1728
0
            xmlChar *name;
1729
1730
0
            name = xmlGetProp(cur, BAD_CAST "name");
1731
0
            if (name == NULL) {
1732
0
                xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
1733
0
                           "xmlRelaxNG: include %s has define without name\n",
1734
0
                           URL, NULL);
1735
0
            } else {
1736
0
                int found;
1737
1738
0
                xmlRelaxNGNormExtSpace(name);
1739
0
                found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1740
0
                                                 root->children, name);
1741
0
                if (!found) {
1742
0
                    xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
1743
0
                               "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1744
0
                               URL, name);
1745
0
                }
1746
0
                xmlFree(name);
1747
0
            }
1748
0
        }
1749
0
        if (IS_RELAXNG(cur, "div") && cur->children != NULL) {
1750
0
            cur = cur->children;
1751
0
        } else {
1752
0
            if (cur->next != NULL) {
1753
0
                cur = cur->next;
1754
0
            } else {
1755
0
                while (cur->parent != node && cur->parent->next == NULL) {
1756
0
                    cur = cur->parent;
1757
0
                }
1758
0
                cur = cur->parent != node ? cur->parent->next : NULL;
1759
0
            }
1760
0
        }
1761
0
    }
1762
1763
1764
0
    return (ret);
1765
0
}
1766
1767
/**
1768
 * xmlRelaxNGValidErrorPush:
1769
 * @ctxt:  the validation context
1770
 * @err:  the error code
1771
 * @arg1:  the first string argument
1772
 * @arg2:  the second string argument
1773
 * @dup:  arg need to be duplicated
1774
 *
1775
 * Pushes a new error on top of the error stack
1776
 *
1777
 * Returns 0 in case of error, the index in the stack otherwise
1778
 */
1779
static int
1780
xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
1781
                         xmlRelaxNGValidErr err, const xmlChar * arg1,
1782
                         const xmlChar * arg2, int dup)
1783
0
{
1784
0
    xmlRelaxNGValidErrorPtr cur;
1785
1786
#ifdef DEBUG_ERROR
1787
    xmlGenericError(xmlGenericErrorContext,
1788
                    "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1789
#endif
1790
0
    if (ctxt->errTab == NULL) {
1791
0
        ctxt->errMax = 8;
1792
0
        ctxt->errNr = 0;
1793
0
        ctxt->errTab =
1794
0
            (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
1795
0
                                                sizeof
1796
0
                                                (xmlRelaxNGValidError));
1797
0
        if (ctxt->errTab == NULL) {
1798
0
            xmlRngVErrMemory(ctxt, "pushing error\n");
1799
0
            return (0);
1800
0
        }
1801
0
        ctxt->err = NULL;
1802
0
    }
1803
0
    if (ctxt->errNr >= ctxt->errMax) {
1804
0
        ctxt->errMax *= 2;
1805
0
        ctxt->errTab =
1806
0
            (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
1807
0
                                                 ctxt->errMax *
1808
0
                                                 sizeof
1809
0
                                                 (xmlRelaxNGValidError));
1810
0
        if (ctxt->errTab == NULL) {
1811
0
            xmlRngVErrMemory(ctxt, "pushing error\n");
1812
0
            return (0);
1813
0
        }
1814
0
        ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1815
0
    }
1816
0
    if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
1817
0
        (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
1818
0
        return (ctxt->errNr);
1819
0
    cur = &ctxt->errTab[ctxt->errNr];
1820
0
    cur->err = err;
1821
0
    if (dup) {
1822
0
        cur->arg1 = xmlStrdup(arg1);
1823
0
        cur->arg2 = xmlStrdup(arg2);
1824
0
        cur->flags = ERROR_IS_DUP;
1825
0
    } else {
1826
0
        cur->arg1 = arg1;
1827
0
        cur->arg2 = arg2;
1828
0
        cur->flags = 0;
1829
0
    }
1830
0
    if (ctxt->state != NULL) {
1831
0
        cur->node = ctxt->state->node;
1832
0
        cur->seq = ctxt->state->seq;
1833
0
    } else {
1834
0
        cur->node = NULL;
1835
0
        cur->seq = NULL;
1836
0
    }
1837
0
    ctxt->err = cur;
1838
0
    return (ctxt->errNr++);
1839
0
}
1840
1841
/**
1842
 * xmlRelaxNGValidErrorPop:
1843
 * @ctxt: the validation context
1844
 *
1845
 * Pops the top error from the error stack
1846
 */
1847
static void
1848
xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1849
0
{
1850
0
    xmlRelaxNGValidErrorPtr cur;
1851
1852
0
    if (ctxt->errNr <= 0) {
1853
0
        ctxt->err = NULL;
1854
0
        return;
1855
0
    }
1856
0
    ctxt->errNr--;
1857
0
    if (ctxt->errNr > 0)
1858
0
        ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1859
0
    else
1860
0
        ctxt->err = NULL;
1861
0
    cur = &ctxt->errTab[ctxt->errNr];
1862
0
    if (cur->flags & ERROR_IS_DUP) {
1863
0
        if (cur->arg1 != NULL)
1864
0
            xmlFree((xmlChar *) cur->arg1);
1865
0
        cur->arg1 = NULL;
1866
0
        if (cur->arg2 != NULL)
1867
0
            xmlFree((xmlChar *) cur->arg2);
1868
0
        cur->arg2 = NULL;
1869
0
        cur->flags = 0;
1870
0
    }
1871
0
}
1872
1873
/**
1874
 * xmlRelaxNGDocumentPush:
1875
 * @ctxt:  the parser context
1876
 * @value:  the element doc
1877
 *
1878
 * Pushes a new doc on top of the doc stack
1879
 *
1880
 * Returns 0 in case of error, the index in the stack otherwise
1881
 */
1882
static int
1883
xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1884
                       xmlRelaxNGDocumentPtr value)
1885
0
{
1886
0
    if (ctxt->docTab == NULL) {
1887
0
        ctxt->docMax = 4;
1888
0
        ctxt->docNr = 0;
1889
0
        ctxt->docTab =
1890
0
            (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
1891
0
                                                sizeof(ctxt->docTab[0]));
1892
0
        if (ctxt->docTab == NULL) {
1893
0
            xmlRngPErrMemory(ctxt, "adding document\n");
1894
0
            return (0);
1895
0
        }
1896
0
    }
1897
0
    if (ctxt->docNr >= ctxt->docMax) {
1898
0
        ctxt->docMax *= 2;
1899
0
        ctxt->docTab =
1900
0
            (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1901
0
                                                 ctxt->docMax *
1902
0
                                                 sizeof(ctxt->docTab[0]));
1903
0
        if (ctxt->docTab == NULL) {
1904
0
            xmlRngPErrMemory(ctxt, "adding document\n");
1905
0
            return (0);
1906
0
        }
1907
0
    }
1908
0
    ctxt->docTab[ctxt->docNr] = value;
1909
0
    ctxt->doc = value;
1910
0
    return (ctxt->docNr++);
1911
0
}
1912
1913
/**
1914
 * xmlRelaxNGDocumentPop:
1915
 * @ctxt: the parser context
1916
 *
1917
 * Pops the top doc from the doc stack
1918
 *
1919
 * Returns the doc just removed
1920
 */
1921
static xmlRelaxNGDocumentPtr
1922
xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1923
0
{
1924
0
    xmlRelaxNGDocumentPtr ret;
1925
1926
0
    if (ctxt->docNr <= 0)
1927
0
        return (NULL);
1928
0
    ctxt->docNr--;
1929
0
    if (ctxt->docNr > 0)
1930
0
        ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1931
0
    else
1932
0
        ctxt->doc = NULL;
1933
0
    ret = ctxt->docTab[ctxt->docNr];
1934
0
    ctxt->docTab[ctxt->docNr] = NULL;
1935
0
    return (ret);
1936
0
}
1937
1938
/**
1939
 * xmlRelaxNGLoadExternalRef:
1940
 * @ctxt: the parser context
1941
 * @URL:  the normalized URL
1942
 * @ns:  the inherited ns if any
1943
 *
1944
 * First lookup if the document is already loaded into the parser context,
1945
 * check against recursion. If not found the resource is loaded and
1946
 * the content is preprocessed before being returned back to the caller.
1947
 *
1948
 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1949
 */
1950
static xmlRelaxNGDocumentPtr
1951
xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
1952
                          const xmlChar * URL, const xmlChar * ns)
1953
0
{
1954
0
    xmlRelaxNGDocumentPtr ret = NULL;
1955
0
    xmlDocPtr doc;
1956
0
    xmlNodePtr root;
1957
0
    int i;
1958
1959
    /*
1960
     * check against recursion in the stack
1961
     */
1962
0
    for (i = 0; i < ctxt->docNr; i++) {
1963
0
        if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1964
0
            xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
1965
0
                       "Detected an externalRef recursion for %s\n", URL,
1966
0
                       NULL);
1967
0
            return (NULL);
1968
0
        }
1969
0
    }
1970
1971
    /*
1972
     * load the document
1973
     */
1974
0
    doc = xmlReadFile((const char *) URL,NULL,0);
1975
0
    if (doc == NULL) {
1976
0
        xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
1977
0
                   "xmlRelaxNG: could not load %s\n", URL, NULL);
1978
0
        return (NULL);
1979
0
    }
1980
1981
    /*
1982
     * Allocate the document structures and register it first.
1983
     */
1984
0
    ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1985
0
    if (ret == NULL) {
1986
0
        xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
1987
0
                   "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
1988
0
        xmlFreeDoc(doc);
1989
0
        return (NULL);
1990
0
    }
1991
0
    memset(ret, 0, sizeof(xmlRelaxNGDocument));
1992
0
    ret->doc = doc;
1993
0
    ret->href = xmlStrdup(URL);
1994
0
    ret->next = ctxt->documents;
1995
0
    ret->externalRef = 1;
1996
0
    ctxt->documents = ret;
1997
1998
    /*
1999
     * transmit the ns if needed
2000
     */
2001
0
    if (ns != NULL) {
2002
0
        root = xmlDocGetRootElement(doc);
2003
0
        if (root != NULL) {
2004
0
            if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
2005
0
                xmlSetProp(root, BAD_CAST "ns", ns);
2006
0
            }
2007
0
        }
2008
0
    }
2009
2010
    /*
2011
     * push it on the stack and register it in the hash table
2012
     */
2013
0
    xmlRelaxNGDocumentPush(ctxt, ret);
2014
2015
    /*
2016
     * Some preprocessing of the document content
2017
     */
2018
0
    doc = xmlRelaxNGCleanupDoc(ctxt, doc);
2019
0
    if (doc == NULL) {
2020
0
        ctxt->doc = NULL;
2021
0
        return (NULL);
2022
0
    }
2023
2024
0
    xmlRelaxNGDocumentPop(ctxt);
2025
2026
0
    return (ret);
2027
0
}
2028
2029
/************************************************************************
2030
 *                  *
2031
 *      Error functions         *
2032
 *                  *
2033
 ************************************************************************/
2034
2035
0
#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2036
0
#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2037
0
#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2038
0
#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2039
0
#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2040
2041
static const char *
2042
xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
2043
0
{
2044
0
    if (def == NULL)
2045
0
        return ("none");
2046
0
    switch (def->type) {
2047
0
        case XML_RELAXNG_EMPTY:
2048
0
            return ("empty");
2049
0
        case XML_RELAXNG_NOT_ALLOWED:
2050
0
            return ("notAllowed");
2051
0
        case XML_RELAXNG_EXCEPT:
2052
0
            return ("except");
2053
0
        case XML_RELAXNG_TEXT:
2054
0
            return ("text");
2055
0
        case XML_RELAXNG_ELEMENT:
2056
0
            return ("element");
2057
0
        case XML_RELAXNG_DATATYPE:
2058
0
            return ("datatype");
2059
0
        case XML_RELAXNG_VALUE:
2060
0
            return ("value");
2061
0
        case XML_RELAXNG_LIST:
2062
0
            return ("list");
2063
0
        case XML_RELAXNG_ATTRIBUTE:
2064
0
            return ("attribute");
2065
0
        case XML_RELAXNG_DEF:
2066
0
            return ("def");
2067
0
        case XML_RELAXNG_REF:
2068
0
            return ("ref");
2069
0
        case XML_RELAXNG_EXTERNALREF:
2070
0
            return ("externalRef");
2071
0
        case XML_RELAXNG_PARENTREF:
2072
0
            return ("parentRef");
2073
0
        case XML_RELAXNG_OPTIONAL:
2074
0
            return ("optional");
2075
0
        case XML_RELAXNG_ZEROORMORE:
2076
0
            return ("zeroOrMore");
2077
0
        case XML_RELAXNG_ONEORMORE:
2078
0
            return ("oneOrMore");
2079
0
        case XML_RELAXNG_CHOICE:
2080
0
            return ("choice");
2081
0
        case XML_RELAXNG_GROUP:
2082
0
            return ("group");
2083
0
        case XML_RELAXNG_INTERLEAVE:
2084
0
            return ("interleave");
2085
0
        case XML_RELAXNG_START:
2086
0
            return ("start");
2087
0
        case XML_RELAXNG_NOOP:
2088
0
            return ("noop");
2089
0
        case XML_RELAXNG_PARAM:
2090
0
            return ("param");
2091
0
    }
2092
0
    return ("unknown");
2093
0
}
2094
2095
/**
2096
 * xmlRelaxNGGetErrorString:
2097
 * @err:  the error code
2098
 * @arg1:  the first string argument
2099
 * @arg2:  the second string argument
2100
 *
2101
 * computes a formatted error string for the given error code and args
2102
 *
2103
 * Returns the error string, it must be deallocated by the caller
2104
 */
2105
static xmlChar *
2106
xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
2107
                         const xmlChar * arg2)
2108
0
{
2109
0
    char msg[1000];
2110
0
    xmlChar *result;
2111
2112
0
    if (arg1 == NULL)
2113
0
        arg1 = BAD_CAST "";
2114
0
    if (arg2 == NULL)
2115
0
        arg2 = BAD_CAST "";
2116
2117
0
    msg[0] = 0;
2118
0
    switch (err) {
2119
0
        case XML_RELAXNG_OK:
2120
0
            return (NULL);
2121
0
        case XML_RELAXNG_ERR_MEMORY:
2122
0
            return (xmlCharStrdup("out of memory\n"));
2123
0
        case XML_RELAXNG_ERR_TYPE:
2124
0
            snprintf(msg, 1000, "failed to validate type %s\n", arg1);
2125
0
            break;
2126
0
        case XML_RELAXNG_ERR_TYPEVAL:
2127
0
            snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
2128
0
                     arg2);
2129
0
            break;
2130
0
        case XML_RELAXNG_ERR_DUPID:
2131
0
            snprintf(msg, 1000, "ID %s redefined\n", arg1);
2132
0
            break;
2133
0
        case XML_RELAXNG_ERR_TYPECMP:
2134
0
            snprintf(msg, 1000, "failed to compare type %s\n", arg1);
2135
0
            break;
2136
0
        case XML_RELAXNG_ERR_NOSTATE:
2137
0
            return (xmlCharStrdup("Internal error: no state\n"));
2138
0
        case XML_RELAXNG_ERR_NODEFINE:
2139
0
            return (xmlCharStrdup("Internal error: no define\n"));
2140
0
        case XML_RELAXNG_ERR_INTERNAL:
2141
0
            snprintf(msg, 1000, "Internal error: %s\n", arg1);
2142
0
            break;
2143
0
        case XML_RELAXNG_ERR_LISTEXTRA:
2144
0
            snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
2145
0
            break;
2146
0
        case XML_RELAXNG_ERR_INTERNODATA:
2147
0
            return (xmlCharStrdup
2148
0
                    ("Internal: interleave block has no data\n"));
2149
0
        case XML_RELAXNG_ERR_INTERSEQ:
2150
0
            return (xmlCharStrdup("Invalid sequence in interleave\n"));
2151
0
        case XML_RELAXNG_ERR_INTEREXTRA:
2152
0
            snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
2153
0
            break;
2154
0
        case XML_RELAXNG_ERR_ELEMNAME:
2155
0
            snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
2156
0
                     arg2);
2157
0
            break;
2158
0
        case XML_RELAXNG_ERR_ELEMNONS:
2159
0
            snprintf(msg, 1000, "Expecting a namespace for element %s\n",
2160
0
                     arg1);
2161
0
            break;
2162
0
        case XML_RELAXNG_ERR_ELEMWRONGNS:
2163
0
            snprintf(msg, 1000,
2164
0
                     "Element %s has wrong namespace: expecting %s\n", arg1,
2165
0
                     arg2);
2166
0
            break;
2167
0
        case XML_RELAXNG_ERR_ELEMWRONG:
2168
0
            snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
2169
0
            break;
2170
0
        case XML_RELAXNG_ERR_TEXTWRONG:
2171
0
            snprintf(msg, 1000,
2172
0
                     "Did not expect text in element %s content\n", arg1);
2173
0
            break;
2174
0
        case XML_RELAXNG_ERR_ELEMEXTRANS:
2175
0
            snprintf(msg, 1000, "Expecting no namespace for element %s\n",
2176
0
                     arg1);
2177
0
            break;
2178
0
        case XML_RELAXNG_ERR_ELEMNOTEMPTY:
2179
0
            snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
2180
0
            break;
2181
0
        case XML_RELAXNG_ERR_NOELEM:
2182
0
            snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
2183
0
                     arg1);
2184
0
            break;
2185
0
        case XML_RELAXNG_ERR_NOTELEM:
2186
0
            return (xmlCharStrdup("Expecting an element got text\n"));
2187
0
        case XML_RELAXNG_ERR_ATTRVALID:
2188
0
            snprintf(msg, 1000, "Element %s failed to validate attributes\n",
2189
0
                     arg1);
2190
0
            break;
2191
0
        case XML_RELAXNG_ERR_CONTENTVALID:
2192
0
            snprintf(msg, 1000, "Element %s failed to validate content\n",
2193
0
                     arg1);
2194
0
            break;
2195
0
        case XML_RELAXNG_ERR_EXTRACONTENT:
2196
0
            snprintf(msg, 1000, "Element %s has extra content: %s\n",
2197
0
                     arg1, arg2);
2198
0
            break;
2199
0
        case XML_RELAXNG_ERR_INVALIDATTR:
2200
0
            snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
2201
0
                     arg1, arg2);
2202
0
            break;
2203
0
        case XML_RELAXNG_ERR_LACKDATA:
2204
0
            snprintf(msg, 1000, "Datatype element %s contains no data\n",
2205
0
                     arg1);
2206
0
            break;
2207
0
        case XML_RELAXNG_ERR_DATAELEM:
2208
0
            snprintf(msg, 1000, "Datatype element %s has child elements\n",
2209
0
                     arg1);
2210
0
            break;
2211
0
        case XML_RELAXNG_ERR_VALELEM:
2212
0
            snprintf(msg, 1000, "Value element %s has child elements\n",
2213
0
                     arg1);
2214
0
            break;
2215
0
        case XML_RELAXNG_ERR_LISTELEM:
2216
0
            snprintf(msg, 1000, "List element %s has child elements\n",
2217
0
                     arg1);
2218
0
            break;
2219
0
        case XML_RELAXNG_ERR_DATATYPE:
2220
0
            snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
2221
0
            break;
2222
0
        case XML_RELAXNG_ERR_VALUE:
2223
0
            snprintf(msg, 1000, "Error validating value %s\n", arg1);
2224
0
            break;
2225
0
        case XML_RELAXNG_ERR_LIST:
2226
0
            return (xmlCharStrdup("Error validating list\n"));
2227
0
        case XML_RELAXNG_ERR_NOGRAMMAR:
2228
0
            return (xmlCharStrdup("No top grammar defined\n"));
2229
0
        case XML_RELAXNG_ERR_EXTRADATA:
2230
0
            return (xmlCharStrdup("Extra data in the document\n"));
2231
0
        default:
2232
0
            return (xmlCharStrdup("Unknown error !\n"));
2233
0
    }
2234
0
    if (msg[0] == 0) {
2235
0
        snprintf(msg, 1000, "Unknown error code %d\n", err);
2236
0
    }
2237
0
    msg[1000 - 1] = 0;
2238
0
    result = xmlCharStrdup(msg);
2239
0
    return (xmlEscapeFormatString(&result));
2240
0
}
2241
2242
/**
2243
 * xmlRelaxNGShowValidError:
2244
 * @ctxt:  the validation context
2245
 * @err:  the error number
2246
 * @node:  the node
2247
 * @child:  the node child generating the problem.
2248
 * @arg1:  the first argument
2249
 * @arg2:  the second argument
2250
 *
2251
 * Show a validation error.
2252
 */
2253
static void
2254
xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
2255
                         xmlRelaxNGValidErr err, xmlNodePtr node,
2256
                         xmlNodePtr child, const xmlChar * arg1,
2257
                         const xmlChar * arg2)
2258
0
{
2259
0
    xmlChar *msg;
2260
2261
0
    if (ctxt->flags & FLAGS_NOERROR)
2262
0
        return;
2263
2264
#ifdef DEBUG_ERROR
2265
    xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
2266
#endif
2267
0
    msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2268
0
    if (msg == NULL)
2269
0
        return;
2270
2271
0
    if (ctxt->errNo == XML_RELAXNG_OK)
2272
0
        ctxt->errNo = err;
2273
0
    xmlRngVErr(ctxt, (child == NULL ? node : child), err,
2274
0
               (const char *) msg, arg1, arg2);
2275
0
    xmlFree(msg);
2276
0
}
2277
2278
/**
2279
 * xmlRelaxNGPopErrors:
2280
 * @ctxt:  the validation context
2281
 * @level:  the error level in the stack
2282
 *
2283
 * pop and discard all errors until the given level is reached
2284
 */
2285
static void
2286
xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
2287
0
{
2288
0
    int i;
2289
0
    xmlRelaxNGValidErrorPtr err;
2290
2291
#ifdef DEBUG_ERROR
2292
    xmlGenericError(xmlGenericErrorContext,
2293
                    "Pop errors till level %d\n", level);
2294
#endif
2295
0
    for (i = level; i < ctxt->errNr; i++) {
2296
0
        err = &ctxt->errTab[i];
2297
0
        if (err->flags & ERROR_IS_DUP) {
2298
0
            if (err->arg1 != NULL)
2299
0
                xmlFree((xmlChar *) err->arg1);
2300
0
            err->arg1 = NULL;
2301
0
            if (err->arg2 != NULL)
2302
0
                xmlFree((xmlChar *) err->arg2);
2303
0
            err->arg2 = NULL;
2304
0
            err->flags = 0;
2305
0
        }
2306
0
    }
2307
0
    ctxt->errNr = level;
2308
0
    if (ctxt->errNr <= 0)
2309
0
        ctxt->err = NULL;
2310
0
}
2311
2312
/**
2313
 * xmlRelaxNGDumpValidError:
2314
 * @ctxt:  the validation context
2315
 *
2316
 * Show all validation error over a given index.
2317
 */
2318
static void
2319
xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
2320
0
{
2321
0
    int i, j, k;
2322
0
    xmlRelaxNGValidErrorPtr err, dup;
2323
2324
#ifdef DEBUG_ERROR
2325
    xmlGenericError(xmlGenericErrorContext,
2326
                    "Dumping error stack %d errors\n", ctxt->errNr);
2327
#endif
2328
0
    for (i = 0, k = 0; i < ctxt->errNr; i++) {
2329
0
        err = &ctxt->errTab[i];
2330
0
        if (k < MAX_ERROR) {
2331
0
            for (j = 0; j < i; j++) {
2332
0
                dup = &ctxt->errTab[j];
2333
0
                if ((err->err == dup->err) && (err->node == dup->node) &&
2334
0
                    (xmlStrEqual(err->arg1, dup->arg1)) &&
2335
0
                    (xmlStrEqual(err->arg2, dup->arg2))) {
2336
0
                    goto skip;
2337
0
                }
2338
0
            }
2339
0
            xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2340
0
                                     err->arg1, err->arg2);
2341
0
            k++;
2342
0
        }
2343
0
      skip:
2344
0
        if (err->flags & ERROR_IS_DUP) {
2345
0
            if (err->arg1 != NULL)
2346
0
                xmlFree((xmlChar *) err->arg1);
2347
0
            err->arg1 = NULL;
2348
0
            if (err->arg2 != NULL)
2349
0
                xmlFree((xmlChar *) err->arg2);
2350
0
            err->arg2 = NULL;
2351
0
            err->flags = 0;
2352
0
        }
2353
0
    }
2354
0
    ctxt->errNr = 0;
2355
0
}
2356
2357
/**
2358
 * xmlRelaxNGAddValidError:
2359
 * @ctxt:  the validation context
2360
 * @err:  the error number
2361
 * @arg1:  the first argument
2362
 * @arg2:  the second argument
2363
 * @dup:  need to dup the args
2364
 *
2365
 * Register a validation error, either generating it if it's sure
2366
 * or stacking it for later handling if unsure.
2367
 */
2368
static void
2369
xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
2370
                        xmlRelaxNGValidErr err, const xmlChar * arg1,
2371
                        const xmlChar * arg2, int dup)
2372
0
{
2373
0
    if (ctxt == NULL)
2374
0
        return;
2375
0
    if (ctxt->flags & FLAGS_NOERROR)
2376
0
        return;
2377
2378
#ifdef DEBUG_ERROR
2379
    xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
2380
#endif
2381
    /*
2382
     * generate the error directly
2383
     */
2384
0
    if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
2385
0
   (ctxt->flags & FLAGS_NEGATIVE)) {
2386
0
        xmlNodePtr node, seq;
2387
2388
        /*
2389
         * Flush first any stacked error which might be the
2390
         * real cause of the problem.
2391
         */
2392
0
        if (ctxt->errNr != 0)
2393
0
            xmlRelaxNGDumpValidError(ctxt);
2394
0
        if (ctxt->state != NULL) {
2395
0
            node = ctxt->state->node;
2396
0
            seq = ctxt->state->seq;
2397
0
        } else {
2398
0
            node = seq = NULL;
2399
0
        }
2400
0
        if ((node == NULL) && (seq == NULL)) {
2401
0
            node = ctxt->pnode;
2402
0
        }
2403
0
        xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2404
0
    }
2405
    /*
2406
     * Stack the error for later processing if needed
2407
     */
2408
0
    else {
2409
0
        xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
2410
0
    }
2411
0
}
2412
2413
2414
/************************************************************************
2415
 *                  *
2416
 *      Type library hooks        *
2417
 *                  *
2418
 ************************************************************************/
2419
static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2420
                                    const xmlChar * str);
2421
2422
/**
2423
 * xmlRelaxNGSchemaTypeHave:
2424
 * @data:  data needed for the library
2425
 * @type:  the type name
2426
 *
2427
 * Check if the given type is provided by
2428
 * the W3C XMLSchema Datatype library.
2429
 *
2430
 * Returns 1 if yes, 0 if no and -1 in case of error.
2431
 */
2432
static int
2433
xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
2434
0
{
2435
0
    xmlSchemaTypePtr typ;
2436
2437
0
    if (type == NULL)
2438
0
        return (-1);
2439
0
    typ = xmlSchemaGetPredefinedType(type,
2440
0
                                     BAD_CAST
2441
0
                                     "http://www.w3.org/2001/XMLSchema");
2442
0
    if (typ == NULL)
2443
0
        return (0);
2444
0
    return (1);
2445
0
}
2446
2447
/**
2448
 * xmlRelaxNGSchemaTypeCheck:
2449
 * @data:  data needed for the library
2450
 * @type:  the type name
2451
 * @value:  the value to check
2452
 * @node:  the node
2453
 *
2454
 * Check if the given type and value are validated by
2455
 * the W3C XMLSchema Datatype library.
2456
 *
2457
 * Returns 1 if yes, 0 if no and -1 in case of error.
2458
 */
2459
static int
2460
xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
2461
                          const xmlChar * type,
2462
                          const xmlChar * value,
2463
                          void **result, xmlNodePtr node)
2464
0
{
2465
0
    xmlSchemaTypePtr typ;
2466
0
    int ret;
2467
2468
0
    if ((type == NULL) || (value == NULL))
2469
0
        return (-1);
2470
0
    typ = xmlSchemaGetPredefinedType(type,
2471
0
                                     BAD_CAST
2472
0
                                     "http://www.w3.org/2001/XMLSchema");
2473
0
    if (typ == NULL)
2474
0
        return (-1);
2475
0
    ret = xmlSchemaValPredefTypeNode(typ, value,
2476
0
                                     (xmlSchemaValPtr *) result, node);
2477
0
    if (ret == 2)               /* special ID error code */
2478
0
        return (2);
2479
0
    if (ret == 0)
2480
0
        return (1);
2481
0
    if (ret > 0)
2482
0
        return (0);
2483
0
    return (-1);
2484
0
}
2485
2486
/**
2487
 * xmlRelaxNGSchemaFacetCheck:
2488
 * @data:  data needed for the library
2489
 * @type:  the type name
2490
 * @facet:  the facet name
2491
 * @val:  the facet value
2492
 * @strval:  the string value
2493
 * @value:  the value to check
2494
 *
2495
 * Function provided by a type library to check a value facet
2496
 *
2497
 * Returns 1 if yes, 0 if no and -1 in case of error.
2498
 */
2499
static int
2500
xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
2501
                           const xmlChar * type, const xmlChar * facetname,
2502
                           const xmlChar * val, const xmlChar * strval,
2503
                           void *value)
2504
0
{
2505
0
    xmlSchemaFacetPtr facet;
2506
0
    xmlSchemaTypePtr typ;
2507
0
    int ret;
2508
2509
0
    if ((type == NULL) || (strval == NULL))
2510
0
        return (-1);
2511
0
    typ = xmlSchemaGetPredefinedType(type,
2512
0
                                     BAD_CAST
2513
0
                                     "http://www.w3.org/2001/XMLSchema");
2514
0
    if (typ == NULL)
2515
0
        return (-1);
2516
2517
0
    facet = xmlSchemaNewFacet();
2518
0
    if (facet == NULL)
2519
0
        return (-1);
2520
2521
0
    if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2522
0
        facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2523
0
    } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2524
0
        facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2525
0
    } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2526
0
        facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2527
0
    } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2528
0
        facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2529
0
    } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2530
0
        facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2531
0
    } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2532
0
        facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2533
0
    } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2534
0
        facet->type = XML_SCHEMA_FACET_PATTERN;
2535
0
    } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2536
0
        facet->type = XML_SCHEMA_FACET_ENUMERATION;
2537
0
    } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2538
0
        facet->type = XML_SCHEMA_FACET_WHITESPACE;
2539
0
    } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2540
0
        facet->type = XML_SCHEMA_FACET_LENGTH;
2541
0
    } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2542
0
        facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2543
0
    } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2544
0
        facet->type = XML_SCHEMA_FACET_MINLENGTH;
2545
0
    } else {
2546
0
        xmlSchemaFreeFacet(facet);
2547
0
        return (-1);
2548
0
    }
2549
0
    facet->value = val;
2550
0
    ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2551
0
    if (ret != 0) {
2552
0
        xmlSchemaFreeFacet(facet);
2553
0
        return (-1);
2554
0
    }
2555
0
    ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2556
0
    xmlSchemaFreeFacet(facet);
2557
0
    if (ret != 0)
2558
0
        return (-1);
2559
0
    return (0);
2560
0
}
2561
2562
/**
2563
 * xmlRelaxNGSchemaFreeValue:
2564
 * @data:  data needed for the library
2565
 * @value:  the value to free
2566
 *
2567
 * Function provided by a type library to free a Schemas value
2568
 *
2569
 * Returns 1 if yes, 0 if no and -1 in case of error.
2570
 */
2571
static void
2572
xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
2573
0
{
2574
0
    xmlSchemaFreeValue(value);
2575
0
}
2576
2577
/**
2578
 * xmlRelaxNGSchemaTypeCompare:
2579
 * @data:  data needed for the library
2580
 * @type:  the type name
2581
 * @value1:  the first value
2582
 * @value2:  the second value
2583
 *
2584
 * Compare two values for equality accordingly a type from the W3C XMLSchema
2585
 * Datatype library.
2586
 *
2587
 * Returns 1 if equal, 0 if no and -1 in case of error.
2588
 */
2589
static int
2590
xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
2591
                            const xmlChar * type,
2592
                            const xmlChar * value1,
2593
                            xmlNodePtr ctxt1,
2594
                            void *comp1,
2595
                            const xmlChar * value2, xmlNodePtr ctxt2)
2596
0
{
2597
0
    int ret;
2598
0
    xmlSchemaTypePtr typ;
2599
0
    xmlSchemaValPtr res1 = NULL, res2 = NULL;
2600
2601
0
    if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2602
0
        return (-1);
2603
0
    typ = xmlSchemaGetPredefinedType(type,
2604
0
                                     BAD_CAST
2605
0
                                     "http://www.w3.org/2001/XMLSchema");
2606
0
    if (typ == NULL)
2607
0
        return (-1);
2608
0
    if (comp1 == NULL) {
2609
0
        ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2610
0
        if (ret != 0)
2611
0
            return (-1);
2612
0
        if (res1 == NULL)
2613
0
            return (-1);
2614
0
    } else {
2615
0
        res1 = (xmlSchemaValPtr) comp1;
2616
0
    }
2617
0
    ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
2618
0
    if (ret != 0) {
2619
0
  if (res1 != (xmlSchemaValPtr) comp1)
2620
0
      xmlSchemaFreeValue(res1);
2621
0
        return (-1);
2622
0
    }
2623
0
    ret = xmlSchemaCompareValues(res1, res2);
2624
0
    if (res1 != (xmlSchemaValPtr) comp1)
2625
0
        xmlSchemaFreeValue(res1);
2626
0
    xmlSchemaFreeValue(res2);
2627
0
    if (ret == -2)
2628
0
        return (-1);
2629
0
    if (ret == 0)
2630
0
        return (1);
2631
0
    return (0);
2632
0
}
2633
2634
/**
2635
 * xmlRelaxNGDefaultTypeHave:
2636
 * @data:  data needed for the library
2637
 * @type:  the type name
2638
 *
2639
 * Check if the given type is provided 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
xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
2646
                          const xmlChar * type)
2647
0
{
2648
0
    if (type == NULL)
2649
0
        return (-1);
2650
0
    if (xmlStrEqual(type, BAD_CAST "string"))
2651
0
        return (1);
2652
0
    if (xmlStrEqual(type, BAD_CAST "token"))
2653
0
        return (1);
2654
0
    return (0);
2655
0
}
2656
2657
/**
2658
 * xmlRelaxNGDefaultTypeCheck:
2659
 * @data:  data needed for the library
2660
 * @type:  the type name
2661
 * @value:  the value to check
2662
 * @node:  the node
2663
 *
2664
 * Check if the given type and value are validated by
2665
 * the default datatype library.
2666
 *
2667
 * Returns 1 if yes, 0 if no and -1 in case of error.
2668
 */
2669
static int
2670
xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2671
                           const xmlChar * type ATTRIBUTE_UNUSED,
2672
                           const xmlChar * value ATTRIBUTE_UNUSED,
2673
                           void **result ATTRIBUTE_UNUSED,
2674
                           xmlNodePtr node ATTRIBUTE_UNUSED)
2675
0
{
2676
0
    if (value == NULL)
2677
0
        return (-1);
2678
0
    if (xmlStrEqual(type, BAD_CAST "string"))
2679
0
        return (1);
2680
0
    if (xmlStrEqual(type, BAD_CAST "token")) {
2681
0
        return (1);
2682
0
    }
2683
2684
0
    return (0);
2685
0
}
2686
2687
/**
2688
 * xmlRelaxNGDefaultTypeCompare:
2689
 * @data:  data needed for the library
2690
 * @type:  the type name
2691
 * @value1:  the first value
2692
 * @value2:  the second value
2693
 *
2694
 * Compare two values accordingly a type from the default
2695
 * datatype library.
2696
 *
2697
 * Returns 1 if yes, 0 if no and -1 in case of error.
2698
 */
2699
static int
2700
xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
2701
                             const xmlChar * type,
2702
                             const xmlChar * value1,
2703
                             xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2704
                             void *comp1 ATTRIBUTE_UNUSED,
2705
                             const xmlChar * value2,
2706
                             xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
2707
0
{
2708
0
    int ret = -1;
2709
2710
0
    if (xmlStrEqual(type, BAD_CAST "string")) {
2711
0
        ret = xmlStrEqual(value1, value2);
2712
0
    } else if (xmlStrEqual(type, BAD_CAST "token")) {
2713
0
        if (!xmlStrEqual(value1, value2)) {
2714
0
            xmlChar *nval, *nvalue;
2715
2716
            /*
2717
             * TODO: trivial optimizations are possible by
2718
             * computing at compile-time
2719
             */
2720
0
            nval = xmlRelaxNGNormalize(NULL, value1);
2721
0
            nvalue = xmlRelaxNGNormalize(NULL, value2);
2722
2723
0
            if ((nval == NULL) || (nvalue == NULL))
2724
0
                ret = -1;
2725
0
            else if (xmlStrEqual(nval, nvalue))
2726
0
                ret = 1;
2727
0
            else
2728
0
                ret = 0;
2729
0
            if (nval != NULL)
2730
0
                xmlFree(nval);
2731
0
            if (nvalue != NULL)
2732
0
                xmlFree(nvalue);
2733
0
        } else
2734
0
            ret = 1;
2735
0
    }
2736
0
    return (ret);
2737
0
}
2738
2739
static int xmlRelaxNGTypeInitialized = 0;
2740
static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2741
2742
/**
2743
 * xmlRelaxNGFreeTypeLibrary:
2744
 * @lib:  the type library structure
2745
 * @namespace:  the URI bound to the library
2746
 *
2747
 * Free the structure associated to the type library
2748
 */
2749
static void
2750
xmlRelaxNGFreeTypeLibrary(void *payload,
2751
                          const xmlChar * namespace ATTRIBUTE_UNUSED)
2752
0
{
2753
0
    xmlRelaxNGTypeLibraryPtr lib = (xmlRelaxNGTypeLibraryPtr) payload;
2754
0
    if (lib == NULL)
2755
0
        return;
2756
0
    if (lib->namespace != NULL)
2757
0
        xmlFree((xmlChar *) lib->namespace);
2758
0
    xmlFree(lib);
2759
0
}
2760
2761
/**
2762
 * xmlRelaxNGRegisterTypeLibrary:
2763
 * @namespace:  the URI bound to the library
2764
 * @data:  data associated to the library
2765
 * @have:  the provide function
2766
 * @check:  the checking function
2767
 * @comp:  the comparison function
2768
 *
2769
 * Register a new type library
2770
 *
2771
 * Returns 0 in case of success and -1 in case of error.
2772
 */
2773
static int
2774
xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
2775
                              xmlRelaxNGTypeHave have,
2776
                              xmlRelaxNGTypeCheck check,
2777
                              xmlRelaxNGTypeCompare comp,
2778
                              xmlRelaxNGFacetCheck facet,
2779
                              xmlRelaxNGTypeFree freef)
2780
0
{
2781
0
    xmlRelaxNGTypeLibraryPtr lib;
2782
0
    int ret;
2783
2784
0
    if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2785
0
        (check == NULL) || (comp == NULL))
2786
0
        return (-1);
2787
0
    if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2788
0
        xmlGenericError(xmlGenericErrorContext,
2789
0
                        "Relax-NG types library '%s' already registered\n",
2790
0
                        namespace);
2791
0
        return (-1);
2792
0
    }
2793
0
    lib =
2794
0
        (xmlRelaxNGTypeLibraryPtr)
2795
0
        xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2796
0
    if (lib == NULL) {
2797
0
        xmlRngVErrMemory(NULL, "adding types library\n");
2798
0
        return (-1);
2799
0
    }
2800
0
    memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2801
0
    lib->namespace = xmlStrdup(namespace);
2802
0
    lib->data = data;
2803
0
    lib->have = have;
2804
0
    lib->comp = comp;
2805
0
    lib->check = check;
2806
0
    lib->facet = facet;
2807
0
    lib->freef = freef;
2808
0
    ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2809
0
    if (ret < 0) {
2810
0
        xmlGenericError(xmlGenericErrorContext,
2811
0
                        "Relax-NG types library failed to register '%s'\n",
2812
0
                        namespace);
2813
0
        xmlRelaxNGFreeTypeLibrary(lib, namespace);
2814
0
        return (-1);
2815
0
    }
2816
0
    return (0);
2817
0
}
2818
2819
/**
2820
 * xmlRelaxNGInitTypes:
2821
 *
2822
 * Initialize the default type libraries.
2823
 *
2824
 * Returns 0 in case of success and -1 in case of error.
2825
 */
2826
int
2827
xmlRelaxNGInitTypes(void)
2828
0
{
2829
0
    if (xmlRelaxNGTypeInitialized != 0)
2830
0
        return (0);
2831
0
    xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2832
0
    if (xmlRelaxNGRegisteredTypes == NULL) {
2833
0
        xmlGenericError(xmlGenericErrorContext,
2834
0
                        "Failed to allocate sh table for Relax-NG types\n");
2835
0
        return (-1);
2836
0
    }
2837
0
    xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2838
0
                                  "http://www.w3.org/2001/XMLSchema-datatypes",
2839
0
                                  NULL, xmlRelaxNGSchemaTypeHave,
2840
0
                                  xmlRelaxNGSchemaTypeCheck,
2841
0
                                  xmlRelaxNGSchemaTypeCompare,
2842
0
                                  xmlRelaxNGSchemaFacetCheck,
2843
0
                                  xmlRelaxNGSchemaFreeValue);
2844
0
    xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
2845
0
                                  xmlRelaxNGDefaultTypeHave,
2846
0
                                  xmlRelaxNGDefaultTypeCheck,
2847
0
                                  xmlRelaxNGDefaultTypeCompare, NULL,
2848
0
                                  NULL);
2849
0
    xmlRelaxNGTypeInitialized = 1;
2850
0
    return (0);
2851
0
}
2852
2853
/**
2854
 * xmlRelaxNGCleanupTypes:
2855
 *
2856
 * DEPRECATED: This function will be made private. Call xmlCleanupParser
2857
 * to free global state but see the warnings there. xmlCleanupParser
2858
 * should be only called once at program exit. In most cases, you don't
2859
 * have call cleanup functions at all.
2860
 *
2861
 * Cleanup the default Schemas type library associated to RelaxNG
2862
 */
2863
void
2864
xmlRelaxNGCleanupTypes(void)
2865
0
{
2866
0
    xmlSchemaCleanupTypes();
2867
0
    if (xmlRelaxNGTypeInitialized == 0)
2868
0
        return;
2869
0
    xmlHashFree(xmlRelaxNGRegisteredTypes, xmlRelaxNGFreeTypeLibrary);
2870
0
    xmlRelaxNGTypeInitialized = 0;
2871
0
}
2872
2873
/************************************************************************
2874
 *                  *
2875
 *    Compiling element content into regexp     *
2876
 *                  *
2877
 * Sometime the element content can be compiled into a pure regexp, *
2878
 * This allows a faster execution and streamability at that level *
2879
 *                  *
2880
 ************************************************************************/
2881
2882
static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2883
                                xmlRelaxNGDefinePtr def);
2884
2885
/**
2886
 * xmlRelaxNGIsCompilable:
2887
 * @define:  the definition to check
2888
 *
2889
 * Check if a definition is nullable.
2890
 *
2891
 * Returns 1 if yes, 0 if no and -1 in case of error
2892
 */
2893
static int
2894
xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def)
2895
0
{
2896
0
    int ret = -1;
2897
2898
0
    if (def == NULL) {
2899
0
        return (-1);
2900
0
    }
2901
0
    if ((def->type != XML_RELAXNG_ELEMENT) &&
2902
0
        (def->dflags & IS_COMPILABLE))
2903
0
        return (1);
2904
0
    if ((def->type != XML_RELAXNG_ELEMENT) &&
2905
0
        (def->dflags & IS_NOT_COMPILABLE))
2906
0
        return (0);
2907
0
    switch (def->type) {
2908
0
        case XML_RELAXNG_NOOP:
2909
0
            ret = xmlRelaxNGIsCompilable(def->content);
2910
0
            break;
2911
0
        case XML_RELAXNG_TEXT:
2912
0
        case XML_RELAXNG_EMPTY:
2913
0
            ret = 1;
2914
0
            break;
2915
0
        case XML_RELAXNG_ELEMENT:
2916
            /*
2917
             * Check if the element content is compilable
2918
             */
2919
0
            if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2920
0
                ((def->dflags & IS_COMPILABLE) == 0)) {
2921
0
                xmlRelaxNGDefinePtr list;
2922
2923
0
                list = def->content;
2924
0
                while (list != NULL) {
2925
0
                    ret = xmlRelaxNGIsCompilable(list);
2926
0
                    if (ret != 1)
2927
0
                        break;
2928
0
                    list = list->next;
2929
0
                }
2930
    /*
2931
     * Because the routine is recursive, we must guard against
2932
     * discovering both COMPILABLE and NOT_COMPILABLE
2933
     */
2934
0
                if (ret == 0) {
2935
0
        def->dflags &= ~IS_COMPILABLE;
2936
0
                    def->dflags |= IS_NOT_COMPILABLE;
2937
0
    }
2938
0
                if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
2939
0
                    def->dflags |= IS_COMPILABLE;
2940
#ifdef DEBUG_COMPILE
2941
                if (ret == 1) {
2942
                    xmlGenericError(xmlGenericErrorContext,
2943
                                    "element content for %s is compilable\n",
2944
                                    def->name);
2945
                } else if (ret == 0) {
2946
                    xmlGenericError(xmlGenericErrorContext,
2947
                                    "element content for %s is not compilable\n",
2948
                                    def->name);
2949
                } else {
2950
                    xmlGenericError(xmlGenericErrorContext,
2951
                                    "Problem in RelaxNGIsCompilable for element %s\n",
2952
                                    def->name);
2953
                }
2954
#endif
2955
0
            }
2956
            /*
2957
             * All elements return a compilable status unless they
2958
             * are generic like anyName
2959
             */
2960
0
            if ((def->nameClass != NULL) || (def->name == NULL))
2961
0
                ret = 0;
2962
0
            else
2963
0
                ret = 1;
2964
0
            return (ret);
2965
0
        case XML_RELAXNG_REF:
2966
0
        case XML_RELAXNG_EXTERNALREF:
2967
0
        case XML_RELAXNG_PARENTREF:
2968
0
            if (def->depth == -20) {
2969
0
                return (1);
2970
0
            } else {
2971
0
                xmlRelaxNGDefinePtr list;
2972
2973
0
                def->depth = -20;
2974
0
                list = def->content;
2975
0
                while (list != NULL) {
2976
0
                    ret = xmlRelaxNGIsCompilable(list);
2977
0
                    if (ret != 1)
2978
0
                        break;
2979
0
                    list = list->next;
2980
0
                }
2981
0
            }
2982
0
            break;
2983
0
        case XML_RELAXNG_START:
2984
0
        case XML_RELAXNG_OPTIONAL:
2985
0
        case XML_RELAXNG_ZEROORMORE:
2986
0
        case XML_RELAXNG_ONEORMORE:
2987
0
        case XML_RELAXNG_CHOICE:
2988
0
        case XML_RELAXNG_GROUP:
2989
0
        case XML_RELAXNG_DEF:{
2990
0
                xmlRelaxNGDefinePtr list;
2991
2992
0
                list = def->content;
2993
0
                while (list != NULL) {
2994
0
                    ret = xmlRelaxNGIsCompilable(list);
2995
0
                    if (ret != 1)
2996
0
                        break;
2997
0
                    list = list->next;
2998
0
                }
2999
0
                break;
3000
0
            }
3001
0
        case XML_RELAXNG_EXCEPT:
3002
0
        case XML_RELAXNG_ATTRIBUTE:
3003
0
        case XML_RELAXNG_INTERLEAVE:
3004
0
        case XML_RELAXNG_DATATYPE:
3005
0
        case XML_RELAXNG_LIST:
3006
0
        case XML_RELAXNG_PARAM:
3007
0
        case XML_RELAXNG_VALUE:
3008
0
        case XML_RELAXNG_NOT_ALLOWED:
3009
0
            ret = 0;
3010
0
            break;
3011
0
    }
3012
0
    if (ret == 0)
3013
0
        def->dflags |= IS_NOT_COMPILABLE;
3014
0
    if (ret == 1)
3015
0
        def->dflags |= IS_COMPILABLE;
3016
#ifdef DEBUG_COMPILE
3017
    if (ret == 1) {
3018
        xmlGenericError(xmlGenericErrorContext,
3019
                        "RelaxNGIsCompilable %s : true\n",
3020
                        xmlRelaxNGDefName(def));
3021
    } else if (ret == 0) {
3022
        xmlGenericError(xmlGenericErrorContext,
3023
                        "RelaxNGIsCompilable %s : false\n",
3024
                        xmlRelaxNGDefName(def));
3025
    } else {
3026
        xmlGenericError(xmlGenericErrorContext,
3027
                        "Problem in RelaxNGIsCompilable %s\n",
3028
                        xmlRelaxNGDefName(def));
3029
    }
3030
#endif
3031
0
    return (ret);
3032
0
}
3033
3034
/**
3035
 * xmlRelaxNGCompile:
3036
 * ctxt:  the RelaxNG parser context
3037
 * @define:  the definition tree to compile
3038
 *
3039
 * Compile the set of definitions, it works recursively, till the
3040
 * element boundaries, where it tries to compile the content if possible
3041
 *
3042
 * Returns 0 if success and -1 in case of error
3043
 */
3044
static int
3045
xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3046
0
{
3047
0
    int ret = 0;
3048
0
    xmlRelaxNGDefinePtr list;
3049
3050
0
    if ((ctxt == NULL) || (def == NULL))
3051
0
        return (-1);
3052
3053
0
    switch (def->type) {
3054
0
        case XML_RELAXNG_START:
3055
0
            if ((xmlRelaxNGIsCompilable(def) == 1) && (def->depth != -25)) {
3056
0
                xmlAutomataPtr oldam = ctxt->am;
3057
0
                xmlAutomataStatePtr oldstate = ctxt->state;
3058
3059
0
                def->depth = -25;
3060
3061
0
                list = def->content;
3062
0
                ctxt->am = xmlNewAutomata();
3063
0
                if (ctxt->am == NULL)
3064
0
                    return (-1);
3065
3066
                /*
3067
                 * assume identical strings but not same pointer are different
3068
                 * atoms, needed for non-determinism detection
3069
                 * That way if 2 elements with the same name are in a choice
3070
                 * branch the automata is found non-deterministic and
3071
                 * we fallback to the normal validation which does the right
3072
                 * thing of exploring both choices.
3073
                 */
3074
0
                xmlAutomataSetFlags(ctxt->am, 1);
3075
3076
0
                ctxt->state = xmlAutomataGetInitState(ctxt->am);
3077
0
                while (list != NULL) {
3078
0
                    xmlRelaxNGCompile(ctxt, list);
3079
0
                    list = list->next;
3080
0
                }
3081
0
                xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3082
0
                if (xmlAutomataIsDeterminist(ctxt->am))
3083
0
                    def->contModel = xmlAutomataCompile(ctxt->am);
3084
3085
0
                xmlFreeAutomata(ctxt->am);
3086
0
                ctxt->state = oldstate;
3087
0
                ctxt->am = oldam;
3088
0
            }
3089
0
            break;
3090
0
        case XML_RELAXNG_ELEMENT:
3091
0
            if ((ctxt->am != NULL) && (def->name != NULL)) {
3092
0
                ctxt->state = xmlAutomataNewTransition2(ctxt->am,
3093
0
                                                        ctxt->state, NULL,
3094
0
                                                        def->name, def->ns,
3095
0
                                                        def);
3096
0
            }
3097
0
            if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3098
0
                xmlAutomataPtr oldam = ctxt->am;
3099
0
                xmlAutomataStatePtr oldstate = ctxt->state;
3100
3101
0
                def->depth = -25;
3102
3103
0
                list = def->content;
3104
0
                ctxt->am = xmlNewAutomata();
3105
0
                if (ctxt->am == NULL)
3106
0
                    return (-1);
3107
0
                xmlAutomataSetFlags(ctxt->am, 1);
3108
0
                ctxt->state = xmlAutomataGetInitState(ctxt->am);
3109
0
                while (list != NULL) {
3110
0
                    xmlRelaxNGCompile(ctxt, list);
3111
0
                    list = list->next;
3112
0
                }
3113
0
                xmlAutomataSetFinalState(ctxt->am, ctxt->state);
3114
0
                def->contModel = xmlAutomataCompile(ctxt->am);
3115
0
                if (!xmlRegexpIsDeterminist(def->contModel)) {
3116
#ifdef DEBUG_COMPILE
3117
                    xmlGenericError(xmlGenericErrorContext,
3118
                        "Content model not determinist %s\n",
3119
                                    def->name);
3120
#endif
3121
                    /*
3122
                     * we can only use the automata if it is determinist
3123
                     */
3124
0
                    xmlRegFreeRegexp(def->contModel);
3125
0
                    def->contModel = NULL;
3126
0
                }
3127
0
                xmlFreeAutomata(ctxt->am);
3128
0
                ctxt->state = oldstate;
3129
0
                ctxt->am = oldam;
3130
0
            } else {
3131
0
                xmlAutomataPtr oldam = ctxt->am;
3132
3133
                /*
3134
                 * we can't build the content model for this element content
3135
                 * but it still might be possible to build it for some of its
3136
                 * children, recurse.
3137
                 */
3138
0
                ret = xmlRelaxNGTryCompile(ctxt, def);
3139
0
                ctxt->am = oldam;
3140
0
            }
3141
0
            break;
3142
0
        case XML_RELAXNG_NOOP:
3143
0
            ret = xmlRelaxNGCompile(ctxt, def->content);
3144
0
            break;
3145
0
        case XML_RELAXNG_OPTIONAL:{
3146
0
                xmlAutomataStatePtr oldstate = ctxt->state;
3147
3148
0
                list = def->content;
3149
0
                while (list != NULL) {
3150
0
                    xmlRelaxNGCompile(ctxt, list);
3151
0
                    list = list->next;
3152
0
                }
3153
0
                xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
3154
0
                break;
3155
0
            }
3156
0
        case XML_RELAXNG_ZEROORMORE:{
3157
0
                xmlAutomataStatePtr oldstate;
3158
3159
0
                ctxt->state =
3160
0
                    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3161
0
                oldstate = ctxt->state;
3162
0
                list = def->content;
3163
0
                while (list != NULL) {
3164
0
                    xmlRelaxNGCompile(ctxt, list);
3165
0
                    list = list->next;
3166
0
                }
3167
0
                xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3168
0
                ctxt->state =
3169
0
                    xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3170
0
                break;
3171
0
            }
3172
0
        case XML_RELAXNG_ONEORMORE:{
3173
0
                xmlAutomataStatePtr oldstate;
3174
3175
0
                list = def->content;
3176
0
                while (list != NULL) {
3177
0
                    xmlRelaxNGCompile(ctxt, list);
3178
0
                    list = list->next;
3179
0
                }
3180
0
                oldstate = ctxt->state;
3181
0
                list = def->content;
3182
0
                while (list != NULL) {
3183
0
                    xmlRelaxNGCompile(ctxt, list);
3184
0
                    list = list->next;
3185
0
                }
3186
0
                xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
3187
0
                ctxt->state =
3188
0
                    xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3189
0
                break;
3190
0
            }
3191
0
        case XML_RELAXNG_CHOICE:{
3192
0
                xmlAutomataStatePtr target = NULL;
3193
0
                xmlAutomataStatePtr oldstate = ctxt->state;
3194
3195
0
                list = def->content;
3196
0
                while (list != NULL) {
3197
0
                    ctxt->state = oldstate;
3198
0
                    ret = xmlRelaxNGCompile(ctxt, list);
3199
0
                    if (ret != 0)
3200
0
                        break;
3201
0
                    if (target == NULL)
3202
0
                        target = ctxt->state;
3203
0
                    else {
3204
0
                        xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
3205
0
                                              target);
3206
0
                    }
3207
0
                    list = list->next;
3208
0
                }
3209
0
                ctxt->state = target;
3210
3211
0
                break;
3212
0
            }
3213
0
        case XML_RELAXNG_REF:
3214
0
        case XML_RELAXNG_EXTERNALREF:
3215
0
        case XML_RELAXNG_PARENTREF:
3216
0
        case XML_RELAXNG_GROUP:
3217
0
        case XML_RELAXNG_DEF:
3218
0
            list = def->content;
3219
0
            while (list != NULL) {
3220
0
                ret = xmlRelaxNGCompile(ctxt, list);
3221
0
                if (ret != 0)
3222
0
                    break;
3223
0
                list = list->next;
3224
0
            }
3225
0
            break;
3226
0
        case XML_RELAXNG_TEXT:{
3227
0
                xmlAutomataStatePtr oldstate;
3228
3229
0
                ctxt->state =
3230
0
                    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3231
0
                oldstate = ctxt->state;
3232
0
                xmlRelaxNGCompile(ctxt, def->content);
3233
0
                xmlAutomataNewTransition(ctxt->am, ctxt->state,
3234
0
                                         ctxt->state, BAD_CAST "#text",
3235
0
                                         NULL);
3236
0
                ctxt->state =
3237
0
                    xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
3238
0
                break;
3239
0
            }
3240
0
        case XML_RELAXNG_EMPTY:
3241
0
            ctxt->state =
3242
0
                xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
3243
0
            break;
3244
0
        case XML_RELAXNG_EXCEPT:
3245
0
        case XML_RELAXNG_ATTRIBUTE:
3246
0
        case XML_RELAXNG_INTERLEAVE:
3247
0
        case XML_RELAXNG_NOT_ALLOWED:
3248
0
        case XML_RELAXNG_DATATYPE:
3249
0
        case XML_RELAXNG_LIST:
3250
0
        case XML_RELAXNG_PARAM:
3251
0
        case XML_RELAXNG_VALUE:
3252
            /* This should not happen and generate an internal error */
3253
0
            fprintf(stderr, "RNG internal error trying to compile %s\n",
3254
0
                    xmlRelaxNGDefName(def));
3255
0
            break;
3256
0
    }
3257
0
    return (ret);
3258
0
}
3259
3260
/**
3261
 * xmlRelaxNGTryCompile:
3262
 * ctxt:  the RelaxNG parser context
3263
 * @define:  the definition tree to compile
3264
 *
3265
 * Try to compile the set of definitions, it works recursively,
3266
 * possibly ignoring parts which cannot be compiled.
3267
 *
3268
 * Returns 0 if success and -1 in case of error
3269
 */
3270
static int
3271
xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
3272
0
{
3273
0
    int ret = 0;
3274
0
    xmlRelaxNGDefinePtr list;
3275
3276
0
    if ((ctxt == NULL) || (def == NULL))
3277
0
        return (-1);
3278
3279
0
    if ((def->type == XML_RELAXNG_START) ||
3280
0
        (def->type == XML_RELAXNG_ELEMENT)) {
3281
0
        ret = xmlRelaxNGIsCompilable(def);
3282
0
        if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
3283
0
            ctxt->am = NULL;
3284
0
            ret = xmlRelaxNGCompile(ctxt, def);
3285
#ifdef DEBUG_PROGRESSIVE
3286
            if (ret == 0) {
3287
                if (def->type == XML_RELAXNG_START)
3288
                    xmlGenericError(xmlGenericErrorContext,
3289
                                    "compiled the start\n");
3290
                else
3291
                    xmlGenericError(xmlGenericErrorContext,
3292
                                    "compiled element %s\n", def->name);
3293
            } else {
3294
                if (def->type == XML_RELAXNG_START)
3295
                    xmlGenericError(xmlGenericErrorContext,
3296
                                    "failed to compile the start\n");
3297
                else
3298
                    xmlGenericError(xmlGenericErrorContext,
3299
                                    "failed to compile element %s\n",
3300
                                    def->name);
3301
            }
3302
#endif
3303
0
            return (ret);
3304
0
        }
3305
0
    }
3306
0
    switch (def->type) {
3307
0
        case XML_RELAXNG_NOOP:
3308
0
            ret = xmlRelaxNGTryCompile(ctxt, def->content);
3309
0
            break;
3310
0
        case XML_RELAXNG_TEXT:
3311
0
        case XML_RELAXNG_DATATYPE:
3312
0
        case XML_RELAXNG_LIST:
3313
0
        case XML_RELAXNG_PARAM:
3314
0
        case XML_RELAXNG_VALUE:
3315
0
        case XML_RELAXNG_EMPTY:
3316
0
        case XML_RELAXNG_ELEMENT:
3317
0
            ret = 0;
3318
0
            break;
3319
0
        case XML_RELAXNG_OPTIONAL:
3320
0
        case XML_RELAXNG_ZEROORMORE:
3321
0
        case XML_RELAXNG_ONEORMORE:
3322
0
        case XML_RELAXNG_CHOICE:
3323
0
        case XML_RELAXNG_GROUP:
3324
0
        case XML_RELAXNG_DEF:
3325
0
        case XML_RELAXNG_START:
3326
0
        case XML_RELAXNG_REF:
3327
0
        case XML_RELAXNG_EXTERNALREF:
3328
0
        case XML_RELAXNG_PARENTREF:
3329
0
            list = def->content;
3330
0
            while (list != NULL) {
3331
0
                ret = xmlRelaxNGTryCompile(ctxt, list);
3332
0
                if (ret != 0)
3333
0
                    break;
3334
0
                list = list->next;
3335
0
            }
3336
0
            break;
3337
0
        case XML_RELAXNG_EXCEPT:
3338
0
        case XML_RELAXNG_ATTRIBUTE:
3339
0
        case XML_RELAXNG_INTERLEAVE:
3340
0
        case XML_RELAXNG_NOT_ALLOWED:
3341
0
            ret = 0;
3342
0
            break;
3343
0
    }
3344
0
    return (ret);
3345
0
}
3346
3347
/************************************************************************
3348
 *                  *
3349
 *      Parsing functions       *
3350
 *                  *
3351
 ************************************************************************/
3352
3353
static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3354
                                                    ctxt, xmlNodePtr node);
3355
static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3356
                                                  ctxt, xmlNodePtr node);
3357
static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3358
                                                   ctxt, xmlNodePtr nodes,
3359
                                                   int group);
3360
static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3361
                                                  ctxt, xmlNodePtr node);
3362
static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
3363
                                             xmlNodePtr node);
3364
static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
3365
                                         xmlNodePtr nodes);
3366
static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3367
                                                    ctxt, xmlNodePtr node,
3368
                                                    xmlRelaxNGDefinePtr
3369
                                                    def);
3370
static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3371
                                                   ctxt, xmlNodePtr nodes);
3372
static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3373
                                  xmlRelaxNGDefinePtr define,
3374
                                  xmlNodePtr elem);
3375
3376
3377
0
#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3378
3379
/**
3380
 * xmlRelaxNGIsNullable:
3381
 * @define:  the definition to verify
3382
 *
3383
 * Check if a definition is nullable.
3384
 *
3385
 * Returns 1 if yes, 0 if no and -1 in case of error
3386
 */
3387
static int
3388
xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
3389
0
{
3390
0
    int ret;
3391
3392
0
    if (define == NULL)
3393
0
        return (-1);
3394
3395
0
    if (define->dflags & IS_NULLABLE)
3396
0
        return (1);
3397
0
    if (define->dflags & IS_NOT_NULLABLE)
3398
0
        return (0);
3399
0
    switch (define->type) {
3400
0
        case XML_RELAXNG_EMPTY:
3401
0
        case XML_RELAXNG_TEXT:
3402
0
            ret = 1;
3403
0
            break;
3404
0
        case XML_RELAXNG_NOOP:
3405
0
        case XML_RELAXNG_DEF:
3406
0
        case XML_RELAXNG_REF:
3407
0
        case XML_RELAXNG_EXTERNALREF:
3408
0
        case XML_RELAXNG_PARENTREF:
3409
0
        case XML_RELAXNG_ONEORMORE:
3410
0
            ret = xmlRelaxNGIsNullable(define->content);
3411
0
            break;
3412
0
        case XML_RELAXNG_EXCEPT:
3413
0
        case XML_RELAXNG_NOT_ALLOWED:
3414
0
        case XML_RELAXNG_ELEMENT:
3415
0
        case XML_RELAXNG_DATATYPE:
3416
0
        case XML_RELAXNG_PARAM:
3417
0
        case XML_RELAXNG_VALUE:
3418
0
        case XML_RELAXNG_LIST:
3419
0
        case XML_RELAXNG_ATTRIBUTE:
3420
0
            ret = 0;
3421
0
            break;
3422
0
        case XML_RELAXNG_CHOICE:{
3423
0
                xmlRelaxNGDefinePtr list = define->content;
3424
3425
0
                while (list != NULL) {
3426
0
                    ret = xmlRelaxNGIsNullable(list);
3427
0
                    if (ret != 0)
3428
0
                        goto done;
3429
0
                    list = list->next;
3430
0
                }
3431
0
                ret = 0;
3432
0
                break;
3433
0
            }
3434
0
        case XML_RELAXNG_START:
3435
0
        case XML_RELAXNG_INTERLEAVE:
3436
0
        case XML_RELAXNG_GROUP:{
3437
0
                xmlRelaxNGDefinePtr list = define->content;
3438
3439
0
                while (list != NULL) {
3440
0
                    ret = xmlRelaxNGIsNullable(list);
3441
0
                    if (ret != 1)
3442
0
                        goto done;
3443
0
                    list = list->next;
3444
0
                }
3445
0
                return (1);
3446
0
            }
3447
0
        default:
3448
0
            return (-1);
3449
0
    }
3450
0
  done:
3451
0
    if (ret == 0)
3452
0
        define->dflags |= IS_NOT_NULLABLE;
3453
0
    if (ret == 1)
3454
0
        define->dflags |= IS_NULLABLE;
3455
0
    return (ret);
3456
0
}
3457
3458
/**
3459
 * xmlRelaxNGIsBlank:
3460
 * @str:  a string
3461
 *
3462
 * Check if a string is ignorable c.f. 4.2. Whitespace
3463
 *
3464
 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3465
 */
3466
static int
3467
xmlRelaxNGIsBlank(xmlChar * str)
3468
0
{
3469
0
    if (str == NULL)
3470
0
        return (1);
3471
0
    while (*str != 0) {
3472
0
        if (!(IS_BLANK_CH(*str)))
3473
0
            return (0);
3474
0
        str++;
3475
0
    }
3476
0
    return (1);
3477
0
}
3478
3479
/**
3480
 * xmlRelaxNGGetDataTypeLibrary:
3481
 * @ctxt:  a Relax-NG parser context
3482
 * @node:  the current data or value element
3483
 *
3484
 * Applies algorithm from 4.3. datatypeLibrary attribute
3485
 *
3486
 * Returns the datatypeLibrary value or NULL if not found
3487
 */
3488
static xmlChar *
3489
xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3490
                             xmlNodePtr node)
3491
0
{
3492
0
    xmlChar *ret, *escape;
3493
3494
0
    if (node == NULL)
3495
0
        return(NULL);
3496
3497
0
    if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3498
0
        ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3499
0
        if (ret != NULL) {
3500
0
            if (ret[0] == 0) {
3501
0
                xmlFree(ret);
3502
0
                return (NULL);
3503
0
            }
3504
0
            escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3505
0
            if (escape == NULL) {
3506
0
                return (ret);
3507
0
            }
3508
0
            xmlFree(ret);
3509
0
            return (escape);
3510
0
        }
3511
0
    }
3512
0
    node = node->parent;
3513
0
    while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
3514
0
        ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3515
0
        if (ret != NULL) {
3516
0
            if (ret[0] == 0) {
3517
0
                xmlFree(ret);
3518
0
                return (NULL);
3519
0
            }
3520
0
            escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3521
0
            if (escape == NULL) {
3522
0
                return (ret);
3523
0
            }
3524
0
            xmlFree(ret);
3525
0
            return (escape);
3526
0
        }
3527
0
        node = node->parent;
3528
0
    }
3529
0
    return (NULL);
3530
0
}
3531
3532
/**
3533
 * xmlRelaxNGParseValue:
3534
 * @ctxt:  a Relax-NG parser context
3535
 * @node:  the data node.
3536
 *
3537
 * parse the content of a RelaxNG value node.
3538
 *
3539
 * Returns the definition pointer or NULL in case of error
3540
 */
3541
static xmlRelaxNGDefinePtr
3542
xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3543
0
{
3544
0
    xmlRelaxNGDefinePtr def = NULL;
3545
0
    xmlRelaxNGTypeLibraryPtr lib = NULL;
3546
0
    xmlChar *type;
3547
0
    xmlChar *library;
3548
0
    int success = 0;
3549
3550
0
    def = xmlRelaxNGNewDefine(ctxt, node);
3551
0
    if (def == NULL)
3552
0
        return (NULL);
3553
0
    def->type = XML_RELAXNG_VALUE;
3554
3555
0
    type = xmlGetProp(node, BAD_CAST "type");
3556
0
    if (type != NULL) {
3557
0
        xmlRelaxNGNormExtSpace(type);
3558
0
        if (xmlValidateNCName(type, 0)) {
3559
0
            xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3560
0
                       "value type '%s' is not an NCName\n", type, NULL);
3561
0
        }
3562
0
        library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3563
0
        if (library == NULL)
3564
0
            library =
3565
0
                xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3566
3567
0
        def->name = type;
3568
0
        def->ns = library;
3569
3570
0
        lib = (xmlRelaxNGTypeLibraryPtr)
3571
0
            xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3572
0
        if (lib == NULL) {
3573
0
            xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3574
0
                       "Use of unregistered type library '%s'\n", library,
3575
0
                       NULL);
3576
0
            def->data = NULL;
3577
0
        } else {
3578
0
            def->data = lib;
3579
0
            if (lib->have == NULL) {
3580
0
                xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3581
0
                           "Internal error with type library '%s': no 'have'\n",
3582
0
                           library, NULL);
3583
0
            } else {
3584
0
                success = lib->have(lib->data, def->name);
3585
0
                if (success != 1) {
3586
0
                    xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3587
0
                               "Error type '%s' is not exported by type library '%s'\n",
3588
0
                               def->name, library);
3589
0
                }
3590
0
            }
3591
0
        }
3592
0
    }
3593
0
    if (node->children == NULL) {
3594
0
        def->value = xmlStrdup(BAD_CAST "");
3595
0
    } else if (((node->children->type != XML_TEXT_NODE) &&
3596
0
                (node->children->type != XML_CDATA_SECTION_NODE)) ||
3597
0
               (node->children->next != NULL)) {
3598
0
        xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
3599
0
                   "Expecting a single text value for <value>content\n",
3600
0
                   NULL, NULL);
3601
0
    } else if (def != NULL) {
3602
0
        def->value = xmlNodeGetContent(node);
3603
0
        if (def->value == NULL) {
3604
0
            xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
3605
0
                       "Element <value> has no content\n", NULL, NULL);
3606
0
        } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3607
0
            void *val = NULL;
3608
3609
0
            success =
3610
0
                lib->check(lib->data, def->name, def->value, &val, node);
3611
0
            if (success != 1) {
3612
0
                xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
3613
0
                           "Value '%s' is not acceptable for type '%s'\n",
3614
0
                           def->value, def->name);
3615
0
            } else {
3616
0
                if (val != NULL)
3617
0
                    def->attrs = val;
3618
0
            }
3619
0
        }
3620
0
    }
3621
0
    return (def);
3622
0
}
3623
3624
/**
3625
 * xmlRelaxNGParseData:
3626
 * @ctxt:  a Relax-NG parser context
3627
 * @node:  the data node.
3628
 *
3629
 * parse the content of a RelaxNG data node.
3630
 *
3631
 * Returns the definition pointer or NULL in case of error
3632
 */
3633
static xmlRelaxNGDefinePtr
3634
xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
3635
0
{
3636
0
    xmlRelaxNGDefinePtr def = NULL, except;
3637
0
    xmlRelaxNGDefinePtr param, lastparam = NULL;
3638
0
    xmlRelaxNGTypeLibraryPtr lib;
3639
0
    xmlChar *type;
3640
0
    xmlChar *library;
3641
0
    xmlNodePtr content;
3642
0
    int tmp;
3643
3644
0
    type = xmlGetProp(node, BAD_CAST "type");
3645
0
    if (type == NULL) {
3646
0
        xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
3647
0
                   NULL);
3648
0
        return (NULL);
3649
0
    }
3650
0
    xmlRelaxNGNormExtSpace(type);
3651
0
    if (xmlValidateNCName(type, 0)) {
3652
0
        xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
3653
0
                   "data type '%s' is not an NCName\n", type, NULL);
3654
0
    }
3655
0
    library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3656
0
    if (library == NULL)
3657
0
        library =
3658
0
            xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3659
3660
0
    def = xmlRelaxNGNewDefine(ctxt, node);
3661
0
    if (def == NULL) {
3662
0
        xmlFree(library);
3663
0
        xmlFree(type);
3664
0
        return (NULL);
3665
0
    }
3666
0
    def->type = XML_RELAXNG_DATATYPE;
3667
0
    def->name = type;
3668
0
    def->ns = library;
3669
3670
0
    lib = (xmlRelaxNGTypeLibraryPtr)
3671
0
        xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3672
0
    if (lib == NULL) {
3673
0
        xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
3674
0
                   "Use of unregistered type library '%s'\n", library,
3675
0
                   NULL);
3676
0
        def->data = NULL;
3677
0
    } else {
3678
0
        def->data = lib;
3679
0
        if (lib->have == NULL) {
3680
0
            xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
3681
0
                       "Internal error with type library '%s': no 'have'\n",
3682
0
                       library, NULL);
3683
0
        } else {
3684
0
            tmp = lib->have(lib->data, def->name);
3685
0
            if (tmp != 1) {
3686
0
                xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
3687
0
                           "Error type '%s' is not exported by type library '%s'\n",
3688
0
                           def->name, library);
3689
0
            } else
3690
0
                if ((xmlStrEqual
3691
0
                     (library,
3692
0
                      BAD_CAST
3693
0
                      "http://www.w3.org/2001/XMLSchema-datatypes"))
3694
0
                    && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
3695
0
                        || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3696
0
                ctxt->idref = 1;
3697
0
            }
3698
0
        }
3699
0
    }
3700
0
    content = node->children;
3701
3702
    /*
3703
     * Handle optional params
3704
     */
3705
0
    while (content != NULL) {
3706
0
        if (!xmlStrEqual(content->name, BAD_CAST "param"))
3707
0
            break;
3708
0
        if (xmlStrEqual(library,
3709
0
                        BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
3710
0
            xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
3711
0
                       "Type library '%s' does not allow type parameters\n",
3712
0
                       library, NULL);
3713
0
            content = content->next;
3714
0
            while ((content != NULL) &&
3715
0
                   (xmlStrEqual(content->name, BAD_CAST "param")))
3716
0
                content = content->next;
3717
0
        } else {
3718
0
            param = xmlRelaxNGNewDefine(ctxt, node);
3719
0
            if (param != NULL) {
3720
0
                param->type = XML_RELAXNG_PARAM;
3721
0
                param->name = xmlGetProp(content, BAD_CAST "name");
3722
0
                if (param->name == NULL) {
3723
0
                    xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
3724
0
                               "param has no name\n", NULL, NULL);
3725
0
                }
3726
0
                param->value = xmlNodeGetContent(content);
3727
0
                if (lastparam == NULL) {
3728
0
                    def->attrs = lastparam = param;
3729
0
                } else {
3730
0
                    lastparam->next = param;
3731
0
                    lastparam = param;
3732
0
                }
3733
0
                if (lib != NULL) {
3734
0
                }
3735
0
            }
3736
0
            content = content->next;
3737
0
        }
3738
0
    }
3739
    /*
3740
     * Handle optional except
3741
     */
3742
0
    if ((content != NULL)
3743
0
        && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3744
0
        xmlNodePtr child;
3745
0
        xmlRelaxNGDefinePtr tmp2, last = NULL;
3746
3747
0
        except = xmlRelaxNGNewDefine(ctxt, node);
3748
0
        if (except == NULL) {
3749
0
            return (def);
3750
0
        }
3751
0
        except->type = XML_RELAXNG_EXCEPT;
3752
0
        child = content->children;
3753
0
  def->content = except;
3754
0
        if (child == NULL) {
3755
0
            xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
3756
0
                       "except has no content\n", NULL, NULL);
3757
0
        }
3758
0
        while (child != NULL) {
3759
0
            tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3760
0
            if (tmp2 != NULL) {
3761
0
                if (last == NULL) {
3762
0
                    except->content = last = tmp2;
3763
0
                } else {
3764
0
                    last->next = tmp2;
3765
0
                    last = tmp2;
3766
0
                }
3767
0
            }
3768
0
            child = child->next;
3769
0
        }
3770
0
        content = content->next;
3771
0
    }
3772
    /*
3773
     * Check there is no unhandled data
3774
     */
3775
0
    if (content != NULL) {
3776
0
        xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
3777
0
                   "Element data has unexpected content %s\n",
3778
0
                   content->name, NULL);
3779
0
    }
3780
3781
0
    return (def);
3782
0
}
3783
3784
static const xmlChar *invalidName = BAD_CAST "\1";
3785
3786
/**
3787
 * xmlRelaxNGCompareNameClasses:
3788
 * @defs1:  the first element/attribute defs
3789
 * @defs2:  the second element/attribute defs
3790
 * @name:  the restriction on the name
3791
 * @ns:  the restriction on the namespace
3792
 *
3793
 * Compare the 2 lists of element definitions. The comparison is
3794
 * that if both lists do not accept the same QNames, it returns 1
3795
 * If the 2 lists can accept the same QName the comparison returns 0
3796
 *
3797
 * Returns 1 distinct, 0 if equal
3798
 */
3799
static int
3800
xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3801
                             xmlRelaxNGDefinePtr def2)
3802
0
{
3803
0
    int ret = 1;
3804
0
    xmlNode node;
3805
0
    xmlNs ns;
3806
0
    xmlRelaxNGValidCtxt ctxt;
3807
3808
0
    memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3809
3810
0
    ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
3811
3812
0
    if ((def1->type == XML_RELAXNG_ELEMENT) ||
3813
0
        (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3814
0
        if (def2->type == XML_RELAXNG_TEXT)
3815
0
            return (1);
3816
0
        if (def1->name != NULL) {
3817
0
            node.name = def1->name;
3818
0
        } else {
3819
0
            node.name = invalidName;
3820
0
        }
3821
0
        if (def1->ns != NULL) {
3822
0
            if (def1->ns[0] == 0) {
3823
0
                node.ns = NULL;
3824
0
            } else {
3825
0
          node.ns = &ns;
3826
0
                ns.href = def1->ns;
3827
0
            }
3828
0
        } else {
3829
0
            node.ns = NULL;
3830
0
        }
3831
0
        if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
3832
0
            if (def1->nameClass != NULL) {
3833
0
                ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3834
0
            } else {
3835
0
                ret = 0;
3836
0
            }
3837
0
        } else {
3838
0
            ret = 1;
3839
0
        }
3840
0
    } else if (def1->type == XML_RELAXNG_TEXT) {
3841
0
        if (def2->type == XML_RELAXNG_TEXT)
3842
0
            return (0);
3843
0
        return (1);
3844
0
    } else if (def1->type == XML_RELAXNG_EXCEPT) {
3845
0
        ret = xmlRelaxNGCompareNameClasses(def1->content, def2);
3846
0
  if (ret == 0)
3847
0
      ret = 1;
3848
0
  else if (ret == 1)
3849
0
      ret = 0;
3850
0
    } else {
3851
0
        TODO ret = 0;
3852
0
    }
3853
0
    if (ret == 0)
3854
0
        return (ret);
3855
0
    if ((def2->type == XML_RELAXNG_ELEMENT) ||
3856
0
        (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3857
0
        if (def2->name != NULL) {
3858
0
            node.name = def2->name;
3859
0
        } else {
3860
0
            node.name = invalidName;
3861
0
        }
3862
0
        node.ns = &ns;
3863
0
        if (def2->ns != NULL) {
3864
0
            if (def2->ns[0] == 0) {
3865
0
                node.ns = NULL;
3866
0
            } else {
3867
0
                ns.href = def2->ns;
3868
0
            }
3869
0
        } else {
3870
0
            ns.href = invalidName;
3871
0
        }
3872
0
        if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
3873
0
            if (def2->nameClass != NULL) {
3874
0
                ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3875
0
            } else {
3876
0
                ret = 0;
3877
0
            }
3878
0
        } else {
3879
0
            ret = 1;
3880
0
        }
3881
0
    } else {
3882
0
        TODO ret = 0;
3883
0
    }
3884
3885
0
    return (ret);
3886
0
}
3887
3888
/**
3889
 * xmlRelaxNGCompareElemDefLists:
3890
 * @ctxt:  a Relax-NG parser context
3891
 * @defs1:  the first list of element/attribute defs
3892
 * @defs2:  the second list of element/attribute defs
3893
 *
3894
 * Compare the 2 lists of element or attribute definitions. The comparison
3895
 * is that if both lists do not accept the same QNames, it returns 1
3896
 * If the 2 lists can accept the same QName the comparison returns 0
3897
 *
3898
 * Returns 1 distinct, 0 if equal
3899
 */
3900
static int
3901
xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3902
                              ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
3903
                              xmlRelaxNGDefinePtr * def2)
3904
0
{
3905
0
    xmlRelaxNGDefinePtr *basedef2 = def2;
3906
3907
0
    if ((def1 == NULL) || (def2 == NULL))
3908
0
        return (1);
3909
0
    if ((*def1 == NULL) || (*def2 == NULL))
3910
0
        return (1);
3911
0
    while (*def1 != NULL) {
3912
0
        while ((*def2) != NULL) {
3913
0
            if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3914
0
                return (0);
3915
0
            def2++;
3916
0
        }
3917
0
        def2 = basedef2;
3918
0
        def1++;
3919
0
    }
3920
0
    return (1);
3921
0
}
3922
3923
/**
3924
 * xmlRelaxNGGenerateAttributes:
3925
 * @ctxt:  a Relax-NG parser context
3926
 * @def:  the definition definition
3927
 *
3928
 * Check if the definition can only generate attributes
3929
 *
3930
 * Returns 1 if yes, 0 if no and -1 in case of error.
3931
 */
3932
static int
3933
xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3934
                             xmlRelaxNGDefinePtr def)
3935
0
{
3936
0
    xmlRelaxNGDefinePtr parent, cur, tmp;
3937
3938
    /*
3939
     * Don't run that check in case of error. Infinite recursion
3940
     * becomes possible.
3941
     */
3942
0
    if (ctxt->nbErrors != 0)
3943
0
        return (-1);
3944
3945
0
    parent = NULL;
3946
0
    cur = def;
3947
0
    while (cur != NULL) {
3948
0
        if ((cur->type == XML_RELAXNG_ELEMENT) ||
3949
0
            (cur->type == XML_RELAXNG_TEXT) ||
3950
0
            (cur->type == XML_RELAXNG_DATATYPE) ||
3951
0
            (cur->type == XML_RELAXNG_PARAM) ||
3952
0
            (cur->type == XML_RELAXNG_LIST) ||
3953
0
            (cur->type == XML_RELAXNG_VALUE) ||
3954
0
            (cur->type == XML_RELAXNG_EMPTY))
3955
0
            return (0);
3956
0
        if ((cur->type == XML_RELAXNG_CHOICE) ||
3957
0
            (cur->type == XML_RELAXNG_INTERLEAVE) ||
3958
0
            (cur->type == XML_RELAXNG_GROUP) ||
3959
0
            (cur->type == XML_RELAXNG_ONEORMORE) ||
3960
0
            (cur->type == XML_RELAXNG_ZEROORMORE) ||
3961
0
            (cur->type == XML_RELAXNG_OPTIONAL) ||
3962
0
            (cur->type == XML_RELAXNG_PARENTREF) ||
3963
0
            (cur->type == XML_RELAXNG_EXTERNALREF) ||
3964
0
            (cur->type == XML_RELAXNG_REF) ||
3965
0
            (cur->type == XML_RELAXNG_DEF)) {
3966
0
            if (cur->content != NULL) {
3967
0
                parent = cur;
3968
0
                cur = cur->content;
3969
0
                tmp = cur;
3970
0
                while (tmp != NULL) {
3971
0
                    tmp->parent = parent;
3972
0
                    tmp = tmp->next;
3973
0
                }
3974
0
                continue;
3975
0
            }
3976
0
        }
3977
0
        if (cur == def)
3978
0
            break;
3979
0
        if (cur->next != NULL) {
3980
0
            cur = cur->next;
3981
0
            continue;
3982
0
        }
3983
0
        do {
3984
0
            cur = cur->parent;
3985
0
            if (cur == NULL)
3986
0
                break;
3987
0
            if (cur == def)
3988
0
                return (1);
3989
0
            if (cur->next != NULL) {
3990
0
                cur = cur->next;
3991
0
                break;
3992
0
            }
3993
0
        } while (cur != NULL);
3994
0
    }
3995
0
    return (1);
3996
0
}
3997
3998
/**
3999
 * xmlRelaxNGGetElements:
4000
 * @ctxt:  a Relax-NG parser context
4001
 * @def:  the definition definition
4002
 * @eora:  gather elements (0), attributes (1) or elements and text (2)
4003
 *
4004
 * Compute the list of top elements a definition can generate
4005
 *
4006
 * Returns a list of elements or NULL if none was found.
4007
 */
4008
static xmlRelaxNGDefinePtr *
4009
xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
4010
                      xmlRelaxNGDefinePtr def, int eora)
4011
0
{
4012
0
    xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
4013
0
    int len = 0;
4014
0
    int max = 0;
4015
4016
    /*
4017
     * Don't run that check in case of error. Infinite recursion
4018
     * becomes possible.
4019
     */
4020
0
    if (ctxt->nbErrors != 0)
4021
0
        return (NULL);
4022
4023
0
    parent = NULL;
4024
0
    cur = def;
4025
0
    while (cur != NULL) {
4026
0
        if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
4027
0
                             (cur->type == XML_RELAXNG_TEXT))) ||
4028
0
            ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE)) ||
4029
0
            ((eora == 2) && ((cur->type == XML_RELAXNG_DATATYPE) ||
4030
0
                       (cur->type == XML_RELAXNG_ELEMENT) ||
4031
0
           (cur->type == XML_RELAXNG_LIST) ||
4032
0
                             (cur->type == XML_RELAXNG_TEXT) ||
4033
0
           (cur->type == XML_RELAXNG_VALUE)))) {
4034
0
            if (ret == NULL) {
4035
0
                max = 10;
4036
0
                ret = (xmlRelaxNGDefinePtr *)
4037
0
                    xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
4038
0
                if (ret == NULL) {
4039
0
                    xmlRngPErrMemory(ctxt, "getting element list\n");
4040
0
                    return (NULL);
4041
0
                }
4042
0
            } else if (max <= len) {
4043
0
          xmlRelaxNGDefinePtr *temp;
4044
4045
0
                max *= 2;
4046
0
                temp = xmlRealloc(ret,
4047
0
                               (max + 1) * sizeof(xmlRelaxNGDefinePtr));
4048
0
                if (temp == NULL) {
4049
0
                    xmlRngPErrMemory(ctxt, "getting element list\n");
4050
0
        xmlFree(ret);
4051
0
                    return (NULL);
4052
0
                }
4053
0
    ret = temp;
4054
0
            }
4055
0
            ret[len++] = cur;
4056
0
            ret[len] = NULL;
4057
0
        } else if ((cur->type == XML_RELAXNG_CHOICE) ||
4058
0
                   (cur->type == XML_RELAXNG_INTERLEAVE) ||
4059
0
                   (cur->type == XML_RELAXNG_GROUP) ||
4060
0
                   (cur->type == XML_RELAXNG_ONEORMORE) ||
4061
0
                   (cur->type == XML_RELAXNG_ZEROORMORE) ||
4062
0
                   (cur->type == XML_RELAXNG_OPTIONAL) ||
4063
0
                   (cur->type == XML_RELAXNG_PARENTREF) ||
4064
0
                   (cur->type == XML_RELAXNG_REF) ||
4065
0
                   (cur->type == XML_RELAXNG_DEF) ||
4066
0
       (cur->type == XML_RELAXNG_EXTERNALREF)) {
4067
            /*
4068
             * Don't go within elements or attributes or string values.
4069
             * Just gather the element top list
4070
             */
4071
0
            if (cur->content != NULL) {
4072
0
                parent = cur;
4073
0
                cur = cur->content;
4074
0
                tmp = cur;
4075
0
                while (tmp != NULL) {
4076
0
                    tmp->parent = parent;
4077
0
                    tmp = tmp->next;
4078
0
                }
4079
0
                continue;
4080
0
            }
4081
0
        }
4082
0
        if (cur == def)
4083
0
            break;
4084
0
        if (cur->next != NULL) {
4085
0
            cur = cur->next;
4086
0
            continue;
4087
0
        }
4088
0
        do {
4089
0
            cur = cur->parent;
4090
0
            if (cur == NULL)
4091
0
                break;
4092
0
            if (cur == def)
4093
0
                return (ret);
4094
0
            if (cur->next != NULL) {
4095
0
                cur = cur->next;
4096
0
                break;
4097
0
            }
4098
0
        } while (cur != NULL);
4099
0
    }
4100
0
    return (ret);
4101
0
}
4102
4103
/**
4104
 * xmlRelaxNGCheckChoiceDeterminism:
4105
 * @ctxt:  a Relax-NG parser context
4106
 * @def:  the choice definition
4107
 *
4108
 * Also used to find indeterministic pattern in choice
4109
 */
4110
static void
4111
xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
4112
                                 xmlRelaxNGDefinePtr def)
4113
0
{
4114
0
    xmlRelaxNGDefinePtr **list;
4115
0
    xmlRelaxNGDefinePtr cur;
4116
0
    int nbchild = 0, i, j, ret;
4117
0
    int is_nullable = 0;
4118
0
    int is_indeterminist = 0;
4119
0
    xmlHashTablePtr triage = NULL;
4120
0
    int is_triable = 1;
4121
4122
0
    if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
4123
0
        return;
4124
4125
0
    if (def->dflags & IS_PROCESSED)
4126
0
        return;
4127
4128
    /*
4129
     * Don't run that check in case of error. Infinite recursion
4130
     * becomes possible.
4131
     */
4132
0
    if (ctxt->nbErrors != 0)
4133
0
        return;
4134
4135
0
    is_nullable = xmlRelaxNGIsNullable(def);
4136
4137
0
    cur = def->content;
4138
0
    while (cur != NULL) {
4139
0
        nbchild++;
4140
0
        cur = cur->next;
4141
0
    }
4142
4143
0
    list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4144
0
                                              sizeof(xmlRelaxNGDefinePtr
4145
0
                                                     *));
4146
0
    if (list == NULL) {
4147
0
        xmlRngPErrMemory(ctxt, "building choice\n");
4148
0
        return;
4149
0
    }
4150
0
    i = 0;
4151
    /*
4152
     * a bit strong but safe
4153
     */
4154
0
    if (is_nullable == 0) {
4155
0
        triage = xmlHashCreate(10);
4156
0
    } else {
4157
0
        is_triable = 0;
4158
0
    }
4159
0
    cur = def->content;
4160
0
    while (cur != NULL) {
4161
0
        list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
4162
0
        if ((list[i] == NULL) || (list[i][0] == NULL)) {
4163
0
            is_triable = 0;
4164
0
        } else if (is_triable == 1) {
4165
0
            xmlRelaxNGDefinePtr *tmp;
4166
0
            int res;
4167
4168
0
            tmp = list[i];
4169
0
            while ((*tmp != NULL) && (is_triable == 1)) {
4170
0
                if ((*tmp)->type == XML_RELAXNG_TEXT) {
4171
0
                    res = xmlHashAddEntry2(triage,
4172
0
                                           BAD_CAST "#text", NULL,
4173
0
                                           (void *) cur);
4174
0
                    if (res != 0)
4175
0
                        is_triable = -1;
4176
0
                } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4177
0
                           ((*tmp)->name != NULL)) {
4178
0
                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4179
0
                        res = xmlHashAddEntry2(triage,
4180
0
                                               (*tmp)->name, NULL,
4181
0
                                               (void *) cur);
4182
0
                    else
4183
0
                        res = xmlHashAddEntry2(triage,
4184
0
                                               (*tmp)->name, (*tmp)->ns,
4185
0
                                               (void *) cur);
4186
0
                    if (res != 0)
4187
0
                        is_triable = -1;
4188
0
                } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4189
0
                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4190
0
                        res = xmlHashAddEntry2(triage,
4191
0
                                               BAD_CAST "#any", NULL,
4192
0
                                               (void *) cur);
4193
0
                    else
4194
0
                        res = xmlHashAddEntry2(triage,
4195
0
                                               BAD_CAST "#any", (*tmp)->ns,
4196
0
                                               (void *) cur);
4197
0
                    if (res != 0)
4198
0
                        is_triable = -1;
4199
0
                } else {
4200
0
                    is_triable = -1;
4201
0
                }
4202
0
                tmp++;
4203
0
            }
4204
0
        }
4205
0
        i++;
4206
0
        cur = cur->next;
4207
0
    }
4208
4209
0
    for (i = 0; i < nbchild; i++) {
4210
0
        if (list[i] == NULL)
4211
0
            continue;
4212
0
        for (j = 0; j < i; j++) {
4213
0
            if (list[j] == NULL)
4214
0
                continue;
4215
0
            ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4216
0
            if (ret == 0) {
4217
0
                is_indeterminist = 1;
4218
0
            }
4219
0
        }
4220
0
    }
4221
0
    for (i = 0; i < nbchild; i++) {
4222
0
        if (list[i] != NULL)
4223
0
            xmlFree(list[i]);
4224
0
    }
4225
4226
0
    xmlFree(list);
4227
0
    if (is_indeterminist) {
4228
0
        def->dflags |= IS_INDETERMINIST;
4229
0
    }
4230
0
    if (is_triable == 1) {
4231
0
        def->dflags |= IS_TRIABLE;
4232
0
        def->data = triage;
4233
0
    } else if (triage != NULL) {
4234
0
        xmlHashFree(triage, NULL);
4235
0
    }
4236
0
    def->dflags |= IS_PROCESSED;
4237
0
}
4238
4239
/**
4240
 * xmlRelaxNGCheckGroupAttrs:
4241
 * @ctxt:  a Relax-NG parser context
4242
 * @def:  the group definition
4243
 *
4244
 * Detects violations of rule 7.3
4245
 */
4246
static void
4247
xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
4248
                          xmlRelaxNGDefinePtr def)
4249
0
{
4250
0
    xmlRelaxNGDefinePtr **list;
4251
0
    xmlRelaxNGDefinePtr cur;
4252
0
    int nbchild = 0, i, j, ret;
4253
4254
0
    if ((def == NULL) ||
4255
0
        ((def->type != XML_RELAXNG_GROUP) &&
4256
0
         (def->type != XML_RELAXNG_ELEMENT)))
4257
0
        return;
4258
4259
0
    if (def->dflags & IS_PROCESSED)
4260
0
        return;
4261
4262
    /*
4263
     * Don't run that check in case of error. Infinite recursion
4264
     * becomes possible.
4265
     */
4266
0
    if (ctxt->nbErrors != 0)
4267
0
        return;
4268
4269
0
    cur = def->attrs;
4270
0
    while (cur != NULL) {
4271
0
        nbchild++;
4272
0
        cur = cur->next;
4273
0
    }
4274
0
    cur = def->content;
4275
0
    while (cur != NULL) {
4276
0
        nbchild++;
4277
0
        cur = cur->next;
4278
0
    }
4279
4280
0
    list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
4281
0
                                              sizeof(xmlRelaxNGDefinePtr
4282
0
                                                     *));
4283
0
    if (list == NULL) {
4284
0
        xmlRngPErrMemory(ctxt, "building group\n");
4285
0
        return;
4286
0
    }
4287
0
    i = 0;
4288
0
    cur = def->attrs;
4289
0
    while (cur != NULL) {
4290
0
        list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4291
0
        i++;
4292
0
        cur = cur->next;
4293
0
    }
4294
0
    cur = def->content;
4295
0
    while (cur != NULL) {
4296
0
        list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
4297
0
        i++;
4298
0
        cur = cur->next;
4299
0
    }
4300
4301
0
    for (i = 0; i < nbchild; i++) {
4302
0
        if (list[i] == NULL)
4303
0
            continue;
4304
0
        for (j = 0; j < i; j++) {
4305
0
            if (list[j] == NULL)
4306
0
                continue;
4307
0
            ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
4308
0
            if (ret == 0) {
4309
0
                xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
4310
0
                           "Attributes conflicts in group\n", NULL, NULL);
4311
0
            }
4312
0
        }
4313
0
    }
4314
0
    for (i = 0; i < nbchild; i++) {
4315
0
        if (list[i] != NULL)
4316
0
            xmlFree(list[i]);
4317
0
    }
4318
4319
0
    xmlFree(list);
4320
0
    def->dflags |= IS_PROCESSED;
4321
0
}
4322
4323
/**
4324
 * xmlRelaxNGComputeInterleaves:
4325
 * @def:  the interleave definition
4326
 * @ctxt:  a Relax-NG parser context
4327
 * @name:  the definition name
4328
 *
4329
 * A lot of work for preprocessing interleave definitions
4330
 * is potentially needed to get a decent execution speed at runtime
4331
 *   - trying to get a total order on the element nodes generated
4332
 *     by the interleaves, order the list of interleave definitions
4333
 *     following that order.
4334
 *   - if <text/> is used to handle mixed content, it is better to
4335
 *     flag this in the define and simplify the runtime checking
4336
 *     algorithm
4337
 */
4338
static void
4339
xmlRelaxNGComputeInterleaves(void *payload, void *data,
4340
                             const xmlChar * name ATTRIBUTE_UNUSED)
4341
0
{
4342
0
    xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4343
0
    xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4344
0
    xmlRelaxNGDefinePtr cur, *tmp;
4345
4346
0
    xmlRelaxNGPartitionPtr partitions = NULL;
4347
0
    xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4348
0
    xmlRelaxNGInterleaveGroupPtr group;
4349
0
    int i, j, ret, res;
4350
0
    int nbgroups = 0;
4351
0
    int nbchild = 0;
4352
0
    int is_mixed = 0;
4353
0
    int is_determinist = 1;
4354
4355
    /*
4356
     * Don't run that check in case of error. Infinite recursion
4357
     * becomes possible.
4358
     */
4359
0
    if (ctxt->nbErrors != 0)
4360
0
        return;
4361
4362
#ifdef DEBUG_INTERLEAVE
4363
    xmlGenericError(xmlGenericErrorContext,
4364
                    "xmlRelaxNGComputeInterleaves(%s)\n", name);
4365
#endif
4366
0
    cur = def->content;
4367
0
    while (cur != NULL) {
4368
0
        nbchild++;
4369
0
        cur = cur->next;
4370
0
    }
4371
4372
#ifdef DEBUG_INTERLEAVE
4373
    xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
4374
#endif
4375
0
    groups = (xmlRelaxNGInterleaveGroupPtr *)
4376
0
        xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4377
0
    if (groups == NULL)
4378
0
        goto error;
4379
0
    cur = def->content;
4380
0
    while (cur != NULL) {
4381
0
        groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4382
0
            xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4383
0
        if (groups[nbgroups] == NULL)
4384
0
            goto error;
4385
0
        if (cur->type == XML_RELAXNG_TEXT)
4386
0
            is_mixed++;
4387
0
        groups[nbgroups]->rule = cur;
4388
0
        groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 2);
4389
0
        groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4390
0
        nbgroups++;
4391
0
        cur = cur->next;
4392
0
    }
4393
#ifdef DEBUG_INTERLEAVE
4394
    xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
4395
#endif
4396
4397
    /*
4398
     * Let's check that all rules makes a partitions according to 7.4
4399
     */
4400
0
    partitions = (xmlRelaxNGPartitionPtr)
4401
0
        xmlMalloc(sizeof(xmlRelaxNGPartition));
4402
0
    if (partitions == NULL)
4403
0
        goto error;
4404
0
    memset(partitions, 0, sizeof(xmlRelaxNGPartition));
4405
0
    partitions->nbgroups = nbgroups;
4406
0
    partitions->triage = xmlHashCreate(nbgroups);
4407
0
    for (i = 0; i < nbgroups; i++) {
4408
0
        group = groups[i];
4409
0
        for (j = i + 1; j < nbgroups; j++) {
4410
0
            if (groups[j] == NULL)
4411
0
                continue;
4412
4413
0
            ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4414
0
                                                groups[j]->defs);
4415
0
            if (ret == 0) {
4416
0
                xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
4417
0
                           "Element or text conflicts in interleave\n",
4418
0
                           NULL, NULL);
4419
0
            }
4420
0
            ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4421
0
                                                groups[j]->attrs);
4422
0
            if (ret == 0) {
4423
0
                xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
4424
0
                           "Attributes conflicts in interleave\n", NULL,
4425
0
                           NULL);
4426
0
            }
4427
0
        }
4428
0
        tmp = group->defs;
4429
0
        if ((tmp != NULL) && (*tmp != NULL)) {
4430
0
            while (*tmp != NULL) {
4431
0
                if ((*tmp)->type == XML_RELAXNG_TEXT) {
4432
0
                    res = xmlHashAddEntry2(partitions->triage,
4433
0
                                           BAD_CAST "#text", NULL,
4434
0
                                           (void *) (ptrdiff_t) (i + 1));
4435
0
                    if (res != 0)
4436
0
                        is_determinist = -1;
4437
0
                } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4438
0
                           ((*tmp)->name != NULL)) {
4439
0
                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4440
0
                        res = xmlHashAddEntry2(partitions->triage,
4441
0
                                               (*tmp)->name, NULL,
4442
0
                                               (void *) (ptrdiff_t) (i + 1));
4443
0
                    else
4444
0
                        res = xmlHashAddEntry2(partitions->triage,
4445
0
                                               (*tmp)->name, (*tmp)->ns,
4446
0
                                               (void *) (ptrdiff_t) (i + 1));
4447
0
                    if (res != 0)
4448
0
                        is_determinist = -1;
4449
0
                } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4450
0
                    if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4451
0
                        res = xmlHashAddEntry2(partitions->triage,
4452
0
                                               BAD_CAST "#any", NULL,
4453
0
                                               (void *) (ptrdiff_t) (i + 1));
4454
0
                    else
4455
0
                        res = xmlHashAddEntry2(partitions->triage,
4456
0
                                               BAD_CAST "#any", (*tmp)->ns,
4457
0
                                               (void *) (ptrdiff_t) (i + 1));
4458
0
                    if ((*tmp)->nameClass != NULL)
4459
0
                        is_determinist = 2;
4460
0
                    if (res != 0)
4461
0
                        is_determinist = -1;
4462
0
                } else {
4463
0
                    is_determinist = -1;
4464
0
                }
4465
0
                tmp++;
4466
0
            }
4467
0
        } else {
4468
0
            is_determinist = 0;
4469
0
        }
4470
0
    }
4471
0
    partitions->groups = groups;
4472
4473
    /*
4474
     * and save the partition list back in the def
4475
     */
4476
0
    def->data = partitions;
4477
0
    if (is_mixed != 0)
4478
0
        def->dflags |= IS_MIXED;
4479
0
    if (is_determinist == 1)
4480
0
        partitions->flags = IS_DETERMINIST;
4481
0
    if (is_determinist == 2)
4482
0
        partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
4483
0
    return;
4484
4485
0
  error:
4486
0
    xmlRngPErrMemory(ctxt, "in interleave computation\n");
4487
0
    if (groups != NULL) {
4488
0
        for (i = 0; i < nbgroups; i++)
4489
0
            if (groups[i] != NULL) {
4490
0
                if (groups[i]->defs != NULL)
4491
0
                    xmlFree(groups[i]->defs);
4492
0
                xmlFree(groups[i]);
4493
0
            }
4494
0
        xmlFree(groups);
4495
0
    }
4496
0
    xmlRelaxNGFreePartition(partitions);
4497
0
}
4498
4499
/**
4500
 * xmlRelaxNGParseInterleave:
4501
 * @ctxt:  a Relax-NG parser context
4502
 * @node:  the data node.
4503
 *
4504
 * parse the content of a RelaxNG interleave node.
4505
 *
4506
 * Returns the definition pointer or NULL in case of error
4507
 */
4508
static xmlRelaxNGDefinePtr
4509
xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4510
0
{
4511
0
    xmlRelaxNGDefinePtr def = NULL;
4512
0
    xmlRelaxNGDefinePtr last = NULL, cur;
4513
0
    xmlNodePtr child;
4514
4515
0
    def = xmlRelaxNGNewDefine(ctxt, node);
4516
0
    if (def == NULL) {
4517
0
        return (NULL);
4518
0
    }
4519
0
    def->type = XML_RELAXNG_INTERLEAVE;
4520
4521
0
    if (ctxt->interleaves == NULL)
4522
0
        ctxt->interleaves = xmlHashCreate(10);
4523
0
    if (ctxt->interleaves == NULL) {
4524
0
        xmlRngPErrMemory(ctxt, "create interleaves\n");
4525
0
    } else {
4526
0
        char name[32];
4527
4528
0
        snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4529
0
        if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4530
0
            xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
4531
0
                       "Failed to add %s to hash table\n",
4532
0
           (const xmlChar *) name, NULL);
4533
0
        }
4534
0
    }
4535
0
    child = node->children;
4536
0
    if (child == NULL) {
4537
0
        xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
4538
0
                   "Element interleave is empty\n", NULL, NULL);
4539
0
    }
4540
0
    while (child != NULL) {
4541
0
        if (IS_RELAXNG(child, "element")) {
4542
0
            cur = xmlRelaxNGParseElement(ctxt, child);
4543
0
        } else {
4544
0
            cur = xmlRelaxNGParsePattern(ctxt, child);
4545
0
        }
4546
0
        if (cur != NULL) {
4547
0
            cur->parent = def;
4548
0
            if (last == NULL) {
4549
0
                def->content = last = cur;
4550
0
            } else {
4551
0
                last->next = cur;
4552
0
                last = cur;
4553
0
            }
4554
0
        }
4555
0
        child = child->next;
4556
0
    }
4557
4558
0
    return (def);
4559
0
}
4560
4561
/**
4562
 * xmlRelaxNGParseInclude:
4563
 * @ctxt:  a Relax-NG parser context
4564
 * @node:  the include node
4565
 *
4566
 * Integrate the content of an include node in the current grammar
4567
 *
4568
 * Returns 0 in case of success or -1 in case of error
4569
 */
4570
static int
4571
xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4572
0
{
4573
0
    xmlRelaxNGIncludePtr incl;
4574
0
    xmlNodePtr root;
4575
0
    int ret = 0, tmp;
4576
4577
0
    incl = node->psvi;
4578
0
    if (incl == NULL) {
4579
0
        xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
4580
0
                   "Include node has no data\n", NULL, NULL);
4581
0
        return (-1);
4582
0
    }
4583
0
    root = xmlDocGetRootElement(incl->doc);
4584
0
    if (root == NULL) {
4585
0
        xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
4586
0
                   NULL, NULL);
4587
0
        return (-1);
4588
0
    }
4589
0
    if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4590
0
        xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
4591
0
                   "Include document root is not a grammar\n", NULL, NULL);
4592
0
        return (-1);
4593
0
    }
4594
4595
    /*
4596
     * Merge the definition from both the include and the internal list
4597
     */
4598
0
    if (root->children != NULL) {
4599
0
        tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4600
0
        if (tmp != 0)
4601
0
            ret = -1;
4602
0
    }
4603
0
    if (node->children != NULL) {
4604
0
        tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4605
0
        if (tmp != 0)
4606
0
            ret = -1;
4607
0
    }
4608
0
    return (ret);
4609
0
}
4610
4611
/**
4612
 * xmlRelaxNGParseDefine:
4613
 * @ctxt:  a Relax-NG parser context
4614
 * @node:  the define node
4615
 *
4616
 * parse the content of a RelaxNG define element node.
4617
 *
4618
 * Returns 0 in case of success or -1 in case of error
4619
 */
4620
static int
4621
xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
4622
0
{
4623
0
    xmlChar *name;
4624
0
    int ret = 0, tmp;
4625
0
    xmlRelaxNGDefinePtr def;
4626
0
    const xmlChar *olddefine;
4627
4628
0
    name = xmlGetProp(node, BAD_CAST "name");
4629
0
    if (name == NULL) {
4630
0
        xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
4631
0
                   "define has no name\n", NULL, NULL);
4632
0
    } else {
4633
0
        xmlRelaxNGNormExtSpace(name);
4634
0
        if (xmlValidateNCName(name, 0)) {
4635
0
            xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
4636
0
                       "define name '%s' is not an NCName\n", name, NULL);
4637
0
        }
4638
0
        def = xmlRelaxNGNewDefine(ctxt, node);
4639
0
        if (def == NULL) {
4640
0
            xmlFree(name);
4641
0
            return (-1);
4642
0
        }
4643
0
        def->type = XML_RELAXNG_DEF;
4644
0
        def->name = name;
4645
0
        if (node->children == NULL) {
4646
0
            xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
4647
0
                       "define has no children\n", NULL, NULL);
4648
0
        } else {
4649
0
            olddefine = ctxt->define;
4650
0
            ctxt->define = name;
4651
0
            def->content =
4652
0
                xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4653
0
            ctxt->define = olddefine;
4654
0
        }
4655
0
        if (ctxt->grammar->defs == NULL)
4656
0
            ctxt->grammar->defs = xmlHashCreate(10);
4657
0
        if (ctxt->grammar->defs == NULL) {
4658
0
            xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4659
0
                       "Could not create definition hash\n", NULL, NULL);
4660
0
            ret = -1;
4661
0
        } else {
4662
0
            tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4663
0
            if (tmp < 0) {
4664
0
                xmlRelaxNGDefinePtr prev;
4665
4666
0
                prev = xmlHashLookup(ctxt->grammar->defs, name);
4667
0
                if (prev == NULL) {
4668
0
                    xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
4669
0
                               "Internal error on define aggregation of %s\n",
4670
0
                               name, NULL);
4671
0
                    ret = -1;
4672
0
                } else {
4673
0
                    while (prev->nextHash != NULL)
4674
0
                        prev = prev->nextHash;
4675
0
                    prev->nextHash = def;
4676
0
                }
4677
0
            }
4678
0
        }
4679
0
    }
4680
0
    return (ret);
4681
0
}
4682
4683
/**
4684
 * xmlRelaxNGParseImportRef:
4685
 * @payload: the parser context
4686
 * @data: the current grammar
4687
 * @name: the reference name
4688
 *
4689
 * Import import one references into the current grammar
4690
 */
4691
static void
4692
0
xmlRelaxNGParseImportRef(void *payload, void *data, const xmlChar *name) {
4693
0
    xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
4694
0
    xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
4695
0
    int tmp;
4696
4697
0
    def->dflags |= IS_EXTERNAL_REF;
4698
4699
0
    tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
4700
0
    if (tmp < 0) {
4701
0
        xmlRelaxNGDefinePtr prev;
4702
4703
0
        prev = (xmlRelaxNGDefinePtr)
4704
0
            xmlHashLookup(ctxt->grammar->refs, def->name);
4705
0
        if (prev == NULL) {
4706
0
            if (def->name != NULL) {
4707
0
                xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4708
0
                           "Error refs definitions '%s'\n",
4709
0
                           def->name, NULL);
4710
0
            } else {
4711
0
                xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
4712
0
                           "Error refs definitions\n",
4713
0
                           NULL, NULL);
4714
0
            }
4715
0
        } else {
4716
0
            def->nextHash = prev->nextHash;
4717
0
            prev->nextHash = def;
4718
0
        }
4719
0
    }
4720
0
}
4721
4722
/**
4723
 * xmlRelaxNGParseImportRefs:
4724
 * @ctxt: the parser context
4725
 * @grammar: the sub grammar
4726
 *
4727
 * Import references from the subgrammar into the current grammar
4728
 *
4729
 * Returns 0 in case of success, -1 in case of failure
4730
 */
4731
static int
4732
xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
4733
0
                          xmlRelaxNGGrammarPtr grammar) {
4734
0
    if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
4735
0
        return(-1);
4736
0
    if (grammar->refs == NULL)
4737
0
        return(0);
4738
0
    if (ctxt->grammar->refs == NULL)
4739
0
        ctxt->grammar->refs = xmlHashCreate(10);
4740
0
    if (ctxt->grammar->refs == NULL) {
4741
0