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