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