Paul Cercueil / libxml2

Dependents:   libiio

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers relaxng.c Source File

relaxng.c

00001 /*
00002  * relaxng.c : implementation of the Relax-NG handling and validity checking
00003  *
00004  * See Copyright for the status of this software.
00005  *
00006  * Daniel Veillard <veillard@redhat.com>
00007  */
00008 
00009 /**
00010  * TODO:
00011  * - add support for DTD compatibility spec
00012  *   http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
00013  * - report better mem allocations pbms at runtime and abort immediately.
00014  */
00015 
00016 #define IN_LIBXML
00017 #include "libxml.h"
00018 
00019 #ifdef LIBXML_SCHEMAS_ENABLED
00020 
00021 #include <string.h>
00022 #include <stdio.h>
00023 #include <libxml/xmlmemory.h>
00024 #include <libxml/parser.h>
00025 #include <libxml/parserInternals.h>
00026 #include <libxml/hash.h>
00027 #include <libxml/uri.h>
00028 
00029 #include <libxml/relaxng.h>
00030 
00031 #include <libxml/xmlschemastypes.h>
00032 #include <libxml/xmlautomata.h>
00033 #include <libxml/xmlregexp.h>
00034 #include <libxml/xmlschemastypes.h>
00035 
00036 /*
00037  * The Relax-NG namespace
00038  */
00039 static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
00040     "http://relaxng.org/ns/structure/1.0";
00041 
00042 #define IS_RELAXNG(node, typ)                       \
00043    ((node != NULL) && (node->ns != NULL) &&             \
00044     (node->type == XML_ELEMENT_NODE) &&                 \
00045     (xmlStrEqual(node->name, (const xmlChar *) typ)) &&     \
00046     (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
00047 
00048 
00049 #if 0
00050 #define DEBUG 1
00051 
00052 #define DEBUG_GRAMMAR 1
00053 
00054 #define DEBUG_CONTENT 1
00055 
00056 #define DEBUG_TYPE 1
00057 
00058 #define DEBUG_VALID 1
00059 
00060 #define DEBUG_INTERLEAVE 1
00061 
00062 #define DEBUG_LIST 1
00063 
00064 #define DEBUG_INCLUDE 1
00065 
00066 #define DEBUG_ERROR 1
00067 
00068 #define DEBUG_COMPILE 1
00069 
00070 #define DEBUG_PROGRESSIVE 1
00071 #endif
00072 
00073 #define MAX_ERROR 5
00074 
00075 #define TODO                                \
00076     xmlGenericError(xmlGenericErrorContext,             \
00077         "Unimplemented block at %s:%d\n",               \
00078             __FILE__, __LINE__);
00079 
00080 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
00081 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
00082 
00083 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
00084 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
00085 
00086 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
00087 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
00088 
00089 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
00090 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
00091 
00092 typedef enum {
00093     XML_RELAXNG_COMBINE_UNDEFINED = 0,  /* undefined */
00094     XML_RELAXNG_COMBINE_CHOICE, /* choice */
00095     XML_RELAXNG_COMBINE_INTERLEAVE      /* interleave */
00096 } xmlRelaxNGCombine;
00097 
00098 typedef enum {
00099     XML_RELAXNG_CONTENT_ERROR = -1,
00100     XML_RELAXNG_CONTENT_EMPTY = 0,
00101     XML_RELAXNG_CONTENT_SIMPLE,
00102     XML_RELAXNG_CONTENT_COMPLEX
00103 } xmlRelaxNGContentType;
00104 
00105 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
00106 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
00107 
00108 struct _xmlRelaxNGGrammar {
00109     xmlRelaxNGGrammarPtr parent;        /* the parent grammar if any */
00110     xmlRelaxNGGrammarPtr children;      /* the children grammar if any */
00111     xmlRelaxNGGrammarPtr next;  /* the next grammar if any */
00112     xmlRelaxNGDefinePtr start;  /* <start> content */
00113     xmlRelaxNGCombine combine;  /* the default combine value */
00114     xmlRelaxNGDefinePtr startList;      /* list of <start> definitions */
00115     xmlHashTablePtr defs;       /* define* */
00116     xmlHashTablePtr refs;       /* references */
00117 };
00118 
00119 
00120 typedef enum {
00121     XML_RELAXNG_NOOP = -1,      /* a no operation from simplification  */
00122     XML_RELAXNG_EMPTY = 0,      /* an empty pattern */
00123     XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */
00124     XML_RELAXNG_EXCEPT,         /* except present in nameclass defs */
00125     XML_RELAXNG_TEXT,           /* textual content */
00126     XML_RELAXNG_ELEMENT,        /* an element */
00127     XML_RELAXNG_DATATYPE,       /* extenal data type definition */
00128     XML_RELAXNG_PARAM,          /* extenal data type parameter */
00129     XML_RELAXNG_VALUE,          /* value from an extenal data type definition */
00130     XML_RELAXNG_LIST,           /* a list of patterns */
00131     XML_RELAXNG_ATTRIBUTE,      /* an attrbute following a pattern */
00132     XML_RELAXNG_DEF,            /* a definition */
00133     XML_RELAXNG_REF,            /* reference to a definition */
00134     XML_RELAXNG_EXTERNALREF,    /* reference to an external def */
00135     XML_RELAXNG_PARENTREF,      /* reference to a def in the parent grammar */
00136     XML_RELAXNG_OPTIONAL,       /* optional patterns */
00137     XML_RELAXNG_ZEROORMORE,     /* zero or more non empty patterns */
00138     XML_RELAXNG_ONEORMORE,      /* one or more non empty patterns */
00139     XML_RELAXNG_CHOICE,         /* a choice between non empty patterns */
00140     XML_RELAXNG_GROUP,          /* a pair/group of non empty patterns */
00141     XML_RELAXNG_INTERLEAVE,     /* interleaving choice of non-empty patterns */
00142     XML_RELAXNG_START           /* Used to keep track of starts on grammars */
00143 } xmlRelaxNGType;
00144 
00145 #define IS_NULLABLE     (1 << 0)
00146 #define IS_NOT_NULLABLE     (1 << 1)
00147 #define IS_INDETERMINIST    (1 << 2)
00148 #define IS_MIXED        (1 << 3)
00149 #define IS_TRIABLE      (1 << 4)
00150 #define IS_PROCESSED        (1 << 5)
00151 #define IS_COMPILABLE       (1 << 6)
00152 #define IS_NOT_COMPILABLE   (1 << 7)
00153 #define IS_EXTERNAL_REF         (1 << 8)
00154 
00155 struct _xmlRelaxNGDefine {
00156     xmlRelaxNGType type;        /* the type of definition */
00157     xmlNodePtr node;            /* the node in the source */
00158     xmlChar *name;              /* the element local name if present */
00159     xmlChar *ns;                /* the namespace local name if present */
00160     xmlChar *value;             /* value when available */
00161     void *data;                 /* data lib or specific pointer */
00162     xmlRelaxNGDefinePtr content;        /* the expected content */
00163     xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
00164     xmlRelaxNGDefinePtr next;   /* list within grouping sequences */
00165     xmlRelaxNGDefinePtr attrs;  /* list of attributes for elements */
00166     xmlRelaxNGDefinePtr nameClass;      /* the nameClass definition if any */
00167     xmlRelaxNGDefinePtr nextHash;       /* next define in defs/refs hash tables */
00168     short depth;                /* used for the cycle detection */
00169     short dflags;               /* define related flags */
00170     xmlRegexpPtr contModel;     /* a compiled content model if available */
00171 };
00172 
00173 /**
00174  * _xmlRelaxNG:
00175  *
00176  * A RelaxNGs definition
00177  */
00178 struct _xmlRelaxNG {
00179     void *_private;             /* unused by the library for users or bindings */
00180     xmlRelaxNGGrammarPtr topgrammar;
00181     xmlDocPtr doc;
00182 
00183     int idref;                  /* requires idref checking */
00184 
00185     xmlHashTablePtr defs;       /* define */
00186     xmlHashTablePtr refs;       /* references */
00187     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
00188     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
00189     int defNr;                  /* number of defines used */
00190     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
00191 
00192 };
00193 
00194 #define XML_RELAXNG_IN_ATTRIBUTE    (1 << 0)
00195 #define XML_RELAXNG_IN_ONEORMORE    (1 << 1)
00196 #define XML_RELAXNG_IN_LIST     (1 << 2)
00197 #define XML_RELAXNG_IN_DATAEXCEPT   (1 << 3)
00198 #define XML_RELAXNG_IN_START        (1 << 4)
00199 #define XML_RELAXNG_IN_OOMGROUP     (1 << 5)
00200 #define XML_RELAXNG_IN_OOMINTERLEAVE    (1 << 6)
00201 #define XML_RELAXNG_IN_EXTERNALREF  (1 << 7)
00202 #define XML_RELAXNG_IN_ANYEXCEPT    (1 << 8)
00203 #define XML_RELAXNG_IN_NSEXCEPT     (1 << 9)
00204 
00205 struct _xmlRelaxNGParserCtxt {
00206     void *userData;             /* user specific data block */
00207     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
00208     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
00209     xmlStructuredErrorFunc serror;
00210     xmlRelaxNGValidErr err;
00211 
00212     xmlRelaxNGPtr schema;       /* The schema in use */
00213     xmlRelaxNGGrammarPtr grammar;       /* the current grammar */
00214     xmlRelaxNGGrammarPtr parentgrammar; /* the parent grammar */
00215     int flags;                  /* parser flags */
00216     int nbErrors;               /* number of errors at parse time */
00217     int nbWarnings;             /* number of warnings at parse time */
00218     const xmlChar *define;      /* the current define scope */
00219     xmlRelaxNGDefinePtr def;    /* the current define */
00220 
00221     int nbInterleaves;
00222     xmlHashTablePtr interleaves;        /* keep track of all the interleaves */
00223 
00224     xmlRelaxNGDocumentPtr documents;    /* all the documents loaded */
00225     xmlRelaxNGIncludePtr includes;      /* all the includes loaded */
00226     xmlChar *URL;
00227     xmlDocPtr document;
00228 
00229     int defNr;                  /* number of defines used */
00230     int defMax;                 /* number of defines aloocated */
00231     xmlRelaxNGDefinePtr *defTab;        /* pointer to the allocated definitions */
00232 
00233     const char *buffer;
00234     int size;
00235 
00236     /* the document stack */
00237     xmlRelaxNGDocumentPtr doc;  /* Current parsed external ref */
00238     int docNr;                  /* Depth of the parsing stack */
00239     int docMax;                 /* Max depth of the parsing stack */
00240     xmlRelaxNGDocumentPtr *docTab;      /* array of docs */
00241 
00242     /* the include stack */
00243     xmlRelaxNGIncludePtr inc;   /* Current parsed include */
00244     int incNr;                  /* Depth of the include parsing stack */
00245     int incMax;                 /* Max depth of the parsing stack */
00246     xmlRelaxNGIncludePtr *incTab;       /* array of incs */
00247 
00248     int idref;                  /* requires idref checking */
00249 
00250     /* used to compile content models */
00251     xmlAutomataPtr am;          /* the automata */
00252     xmlAutomataStatePtr state;  /* used to build the automata */
00253 
00254     int crng;           /* compact syntax and other flags */
00255     int freedoc;        /* need to free the document */
00256 };
00257 
00258 #define FLAGS_IGNORABLE     1
00259 #define FLAGS_NEGATIVE      2
00260 #define FLAGS_MIXED_CONTENT 4
00261 #define FLAGS_NOERROR       8
00262 
00263 /**
00264  * xmlRelaxNGInterleaveGroup:
00265  *
00266  * A RelaxNGs partition set associated to lists of definitions
00267  */
00268 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
00269 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
00270 struct _xmlRelaxNGInterleaveGroup {
00271     xmlRelaxNGDefinePtr rule;   /* the rule to satisfy */
00272     xmlRelaxNGDefinePtr *defs;  /* the array of element definitions */
00273     xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
00274 };
00275 
00276 #define IS_DETERMINIST      1
00277 #define IS_NEEDCHECK        2
00278 
00279 /**
00280  * xmlRelaxNGPartitions:
00281  *
00282  * A RelaxNGs partition associated to an interleave group
00283  */
00284 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
00285 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
00286 struct _xmlRelaxNGPartition {
00287     int nbgroups;               /* number of groups in the partitions */
00288     xmlHashTablePtr triage;     /* hash table used to direct nodes to the
00289                                  * right group when possible */
00290     int flags;                  /* determinist ? */
00291     xmlRelaxNGInterleaveGroupPtr *groups;
00292 };
00293 
00294 /**
00295  * xmlRelaxNGValidState:
00296  *
00297  * A RelaxNGs validation state
00298  */
00299 #define MAX_ATTR 20
00300 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
00301 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
00302 struct _xmlRelaxNGValidState {
00303     xmlNodePtr node;            /* the current node */
00304     xmlNodePtr seq;             /* the sequence of children left to validate */
00305     int nbAttrs;                /* the number of attributes */
00306     int maxAttrs;               /* the size of attrs */
00307     int nbAttrLeft;             /* the number of attributes left to validate */
00308     xmlChar *value;             /* the value when operating on string */
00309     xmlChar *endvalue;          /* the end value when operating on string */
00310     xmlAttrPtr *attrs;          /* the array of attributes */
00311 };
00312 
00313 /**
00314  * xmlRelaxNGStates:
00315  *
00316  * A RelaxNGs container for validation state
00317  */
00318 typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
00319 typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
00320 struct _xmlRelaxNGStates {
00321     int nbState;                /* the number of states */
00322     int maxState;               /* the size of the array */
00323     xmlRelaxNGValidStatePtr *tabState;
00324 };
00325 
00326 #define ERROR_IS_DUP    1
00327 
00328 /**
00329  * xmlRelaxNGValidError:
00330  *
00331  * A RelaxNGs validation error
00332  */
00333 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
00334 typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
00335 struct _xmlRelaxNGValidError {
00336     xmlRelaxNGValidErr err;     /* the error number */
00337     int flags;                  /* flags */
00338     xmlNodePtr node;            /* the current node */
00339     xmlNodePtr seq;             /* the current child */
00340     const xmlChar *arg1;        /* first arg */
00341     const xmlChar *arg2;        /* second arg */
00342 };
00343 
00344 /**
00345  * xmlRelaxNGValidCtxt:
00346  *
00347  * A RelaxNGs validation context
00348  */
00349 
00350 struct _xmlRelaxNGValidCtxt {
00351     void *userData;             /* user specific data block */
00352     xmlRelaxNGValidityErrorFunc error;  /* the callback in case of errors */
00353     xmlRelaxNGValidityWarningFunc warning;      /* the callback in case of warning */
00354     xmlStructuredErrorFunc serror;
00355     int nbErrors;               /* number of errors in validation */
00356 
00357     xmlRelaxNGPtr schema;       /* The schema in use */
00358     xmlDocPtr doc;              /* the document being validated */
00359     int flags;                  /* validation flags */
00360     int depth;                  /* validation depth */
00361     int idref;                  /* requires idref checking */
00362     int errNo;                  /* the first error found */
00363 
00364     /*
00365      * Errors accumulated in branches may have to be stacked to be
00366      * provided back when it's sure they affect validation.
00367      */
00368     xmlRelaxNGValidErrorPtr err;        /* Last error */
00369     int errNr;                  /* Depth of the error stack */
00370     int errMax;                 /* Max depth of the error stack */
00371     xmlRelaxNGValidErrorPtr errTab;     /* stack of errors */
00372 
00373     xmlRelaxNGValidStatePtr state;      /* the current validation state */
00374     xmlRelaxNGStatesPtr states; /* the accumulated state list */
00375 
00376     xmlRelaxNGStatesPtr freeState;      /* the pool of free valid states */
00377     int freeStatesNr;
00378     int freeStatesMax;
00379     xmlRelaxNGStatesPtr *freeStates;    /* the pool of free state groups */
00380 
00381     /*
00382      * This is used for "progressive" validation
00383      */
00384     xmlRegExecCtxtPtr elem;     /* the current element regexp */
00385     int elemNr;                 /* the number of element validated */
00386     int elemMax;                /* the max depth of elements */
00387     xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
00388     int pstate;                 /* progressive state */
00389     xmlNodePtr pnode;           /* the current node */
00390     xmlRelaxNGDefinePtr pdef;   /* the non-streamable definition */
00391     int perr;                   /* signal error in content model
00392                                  * outside the regexp */
00393 };
00394 
00395 /**
00396  * xmlRelaxNGInclude:
00397  *
00398  * Structure associated to a RelaxNGs document element
00399  */
00400 struct _xmlRelaxNGInclude {
00401     xmlRelaxNGIncludePtr next;  /* keep a chain of includes */
00402     xmlChar *href;              /* the normalized href value */
00403     xmlDocPtr doc;              /* the associated XML document */
00404     xmlRelaxNGDefinePtr content;        /* the definitions */
00405     xmlRelaxNGPtr schema;       /* the schema */
00406 };
00407 
00408 /**
00409  * xmlRelaxNGDocument:
00410  *
00411  * Structure associated to a RelaxNGs document element
00412  */
00413 struct _xmlRelaxNGDocument {
00414     xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
00415     xmlChar *href;              /* the normalized href value */
00416     xmlDocPtr doc;              /* the associated XML document */
00417     xmlRelaxNGDefinePtr content;        /* the definitions */
00418     xmlRelaxNGPtr schema;       /* the schema */
00419     int externalRef;            /* 1 if an external ref */
00420 };
00421 
00422 
00423 /************************************************************************
00424  *                                  *
00425  *      Some factorized error routines              *
00426  *                                  *
00427  ************************************************************************/
00428 
00429 /**
00430  * xmlRngPErrMemory:
00431  * @ctxt:  an Relax-NG parser context
00432  * @extra:  extra informations
00433  *
00434  * Handle a redefinition of attribute error
00435  */
00436 static void
00437 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt, const char *extra)
00438 {
00439     xmlStructuredErrorFunc schannel = NULL;
00440     xmlGenericErrorFunc channel = NULL;
00441     void *data = NULL;
00442 
00443     if (ctxt != NULL) {
00444         if (ctxt->serror != NULL)
00445         schannel = ctxt->serror;
00446     else
00447         channel = ctxt->error;
00448         data = ctxt->userData;
00449         ctxt->nbErrors++;
00450     }
00451     if (extra)
00452         __xmlRaiseError(schannel, channel, data,
00453                         NULL, NULL, XML_FROM_RELAXNGP,
00454                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
00455                         NULL, NULL, 0, 0,
00456                         "Memory allocation failed : %s\n", extra);
00457     else
00458         __xmlRaiseError(schannel, channel, data,
00459                         NULL, NULL, XML_FROM_RELAXNGP,
00460                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
00461                         NULL, NULL, 0, 0, "Memory allocation failed\n");
00462 }
00463 
00464 /**
00465  * xmlRngVErrMemory:
00466  * @ctxt:  a Relax-NG validation context
00467  * @extra:  extra informations
00468  *
00469  * Handle a redefinition of attribute error
00470  */
00471 static void
00472 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt, const char *extra)
00473 {
00474     xmlStructuredErrorFunc schannel = NULL;
00475     xmlGenericErrorFunc channel = NULL;
00476     void *data = NULL;
00477 
00478     if (ctxt != NULL) {
00479         if (ctxt->serror != NULL)
00480         schannel = ctxt->serror;
00481     else
00482         channel = ctxt->error;
00483         data = ctxt->userData;
00484         ctxt->nbErrors++;
00485     }
00486     if (extra)
00487         __xmlRaiseError(schannel, channel, data,
00488                         NULL, NULL, XML_FROM_RELAXNGV,
00489                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
00490                         NULL, NULL, 0, 0,
00491                         "Memory allocation failed : %s\n", extra);
00492     else
00493         __xmlRaiseError(schannel, channel, data,
00494                         NULL, NULL, XML_FROM_RELAXNGV,
00495                         XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
00496                         NULL, NULL, 0, 0, "Memory allocation failed\n");
00497 }
00498 
00499 /**
00500  * xmlRngPErr:
00501  * @ctxt:  a Relax-NG parser context
00502  * @node:  the node raising the error
00503  * @error:  the error code
00504  * @msg:  message
00505  * @str1:  extra info
00506  * @str2:  extra info
00507  *
00508  * Handle a Relax NG Parsing error
00509  */
00510 static void
00511 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, int error,
00512            const char *msg, const xmlChar * str1, const xmlChar * str2)
00513 {
00514     xmlStructuredErrorFunc schannel = NULL;
00515     xmlGenericErrorFunc channel = NULL;
00516     void *data = NULL;
00517 
00518     if (ctxt != NULL) {
00519         if (ctxt->serror != NULL)
00520         schannel = ctxt->serror;
00521     else
00522         channel = ctxt->error;
00523         data = ctxt->userData;
00524         ctxt->nbErrors++;
00525     }
00526     __xmlRaiseError(schannel, channel, data,
00527                     NULL, node, XML_FROM_RELAXNGP,
00528                     error, XML_ERR_ERROR, NULL, 0,
00529                     (const char *) str1, (const char *) str2, NULL, 0, 0,
00530                     msg, str1, str2);
00531 }
00532 
00533 /**
00534  * xmlRngVErr:
00535  * @ctxt:  a Relax-NG validation context
00536  * @node:  the node raising the error
00537  * @error:  the error code
00538  * @msg:  message
00539  * @str1:  extra info
00540  * @str2:  extra info
00541  *
00542  * Handle a Relax NG Validation error
00543  */
00544 static void
00545 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node, int error,
00546            const char *msg, const xmlChar * str1, const xmlChar * str2)
00547 {
00548     xmlStructuredErrorFunc schannel = NULL;
00549     xmlGenericErrorFunc channel = NULL;
00550     void *data = NULL;
00551 
00552     if (ctxt != NULL) {
00553         if (ctxt->serror != NULL)
00554         schannel = ctxt->serror;
00555     else
00556         channel = ctxt->error;
00557         data = ctxt->userData;
00558         ctxt->nbErrors++;
00559     }
00560     __xmlRaiseError(schannel, channel, data,
00561                     NULL, node, XML_FROM_RELAXNGV,
00562                     error, XML_ERR_ERROR, NULL, 0,
00563                     (const char *) str1, (const char *) str2, NULL, 0, 0,
00564                     msg, str1, str2);
00565 }
00566 
00567 /************************************************************************
00568  *                                  *
00569  *      Preliminary type checking interfaces            *
00570  *                                  *
00571  ************************************************************************/
00572 
00573 /**
00574  * xmlRelaxNGTypeHave:
00575  * @data:  data needed for the library
00576  * @type:  the type name
00577  * @value:  the value to check
00578  *
00579  * Function provided by a type library to check if a type is exported
00580  *
00581  * Returns 1 if yes, 0 if no and -1 in case of error.
00582  */
00583 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar * type);
00584 
00585 /**
00586  * xmlRelaxNGTypeCheck:
00587  * @data:  data needed for the library
00588  * @type:  the type name
00589  * @value:  the value to check
00590  * @result:  place to store the result if needed
00591  *
00592  * Function provided by a type library to check if a value match a type
00593  *
00594  * Returns 1 if yes, 0 if no and -1 in case of error.
00595  */
00596 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar * type,
00597                                     const xmlChar * value, void **result,
00598                                     xmlNodePtr node);
00599 
00600 /**
00601  * xmlRelaxNGFacetCheck:
00602  * @data:  data needed for the library
00603  * @type:  the type name
00604  * @facet:  the facet name
00605  * @val:  the facet value
00606  * @strval:  the string value
00607  * @value:  the value to check
00608  *
00609  * Function provided by a type library to check a value facet
00610  *
00611  * Returns 1 if yes, 0 if no and -1 in case of error.
00612  */
00613 typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar * type,
00614                                      const xmlChar * facet,
00615                                      const xmlChar * val,
00616                                      const xmlChar * strval, void *value);
00617 
00618 /**
00619  * xmlRelaxNGTypeFree:
00620  * @data:  data needed for the library
00621  * @result:  the value to free
00622  *
00623  * Function provided by a type library to free a returned result
00624  */
00625 typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
00626 
00627 /**
00628  * xmlRelaxNGTypeCompare:
00629  * @data:  data needed for the library
00630  * @type:  the type name
00631  * @value1:  the first value
00632  * @value2:  the second value
00633  *
00634  * Function provided by a type library to compare two values accordingly
00635  * to a type.
00636  *
00637  * Returns 1 if yes, 0 if no and -1 in case of error.
00638  */
00639 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar * type,
00640                                       const xmlChar * value1,
00641                                       xmlNodePtr ctxt1,
00642                                       void *comp1,
00643                                       const xmlChar * value2,
00644                                       xmlNodePtr ctxt2);
00645 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
00646 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
00647 struct _xmlRelaxNGTypeLibrary {
00648     const xmlChar *namespace;   /* the datatypeLibrary value */
00649     void *data;                 /* data needed for the library */
00650     xmlRelaxNGTypeHave have;    /* the export function */
00651     xmlRelaxNGTypeCheck check;  /* the checking function */
00652     xmlRelaxNGTypeCompare comp; /* the compare function */
00653     xmlRelaxNGFacetCheck facet; /* the facet check function */
00654     xmlRelaxNGTypeFree freef;   /* the freeing function */
00655 };
00656 
00657 /************************************************************************
00658  *                                  *
00659  *          Allocation functions                *
00660  *                                  *
00661  ************************************************************************/
00662 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
00663 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
00664 static void xmlRelaxNGNormExtSpace(xmlChar * value);
00665 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
00666 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
00667                                      ATTRIBUTE_UNUSED,
00668                                      xmlRelaxNGValidStatePtr state1,
00669                                      xmlRelaxNGValidStatePtr state2);
00670 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
00671                                      xmlRelaxNGValidStatePtr state);
00672 
00673 /**
00674  * xmlRelaxNGFreeDocument:
00675  * @docu:  a document structure
00676  *
00677  * Deallocate a RelaxNG document structure.
00678  */
00679 static void
00680 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
00681 {
00682     if (docu == NULL)
00683         return;
00684 
00685     if (docu->href != NULL)
00686         xmlFree(docu->href);
00687     if (docu->doc != NULL)
00688         xmlFreeDoc(docu->doc);
00689     if (docu->schema != NULL)
00690         xmlRelaxNGFreeInnerSchema(docu->schema);
00691     xmlFree(docu);
00692 }
00693 
00694 /**
00695  * xmlRelaxNGFreeDocumentList:
00696  * @docu:  a list of  document structure
00697  *
00698  * Deallocate a RelaxNG document structures.
00699  */
00700 static void
00701 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
00702 {
00703     xmlRelaxNGDocumentPtr next;
00704 
00705     while (docu != NULL) {
00706         next = docu->next;
00707         xmlRelaxNGFreeDocument(docu);
00708         docu = next;
00709     }
00710 }
00711 
00712 /**
00713  * xmlRelaxNGFreeInclude:
00714  * @incl:  a include structure
00715  *
00716  * Deallocate a RelaxNG include structure.
00717  */
00718 static void
00719 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
00720 {
00721     if (incl == NULL)
00722         return;
00723 
00724     if (incl->href != NULL)
00725         xmlFree(incl->href);
00726     if (incl->doc != NULL)
00727         xmlFreeDoc(incl->doc);
00728     if (incl->schema != NULL)
00729         xmlRelaxNGFree(incl->schema);
00730     xmlFree(incl);
00731 }
00732 
00733 /**
00734  * xmlRelaxNGFreeIncludeList:
00735  * @incl:  a include structure list
00736  *
00737  * Deallocate a RelaxNG include structure.
00738  */
00739 static void
00740 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
00741 {
00742     xmlRelaxNGIncludePtr next;
00743 
00744     while (incl != NULL) {
00745         next = incl->next;
00746         xmlRelaxNGFreeInclude(incl);
00747         incl = next;
00748     }
00749 }
00750 
00751 /**
00752  * xmlRelaxNGNewRelaxNG:
00753  * @ctxt:  a Relax-NG validation context (optional)
00754  *
00755  * Allocate a new RelaxNG structure.
00756  *
00757  * Returns the newly allocated structure or NULL in case or error
00758  */
00759 static xmlRelaxNGPtr
00760 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
00761 {
00762     xmlRelaxNGPtr ret;
00763 
00764     ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
00765     if (ret == NULL) {
00766         xmlRngPErrMemory(ctxt, NULL);
00767         return (NULL);
00768     }
00769     memset(ret, 0, sizeof(xmlRelaxNG));
00770 
00771     return (ret);
00772 }
00773 
00774 /**
00775  * xmlRelaxNGFreeInnerSchema:
00776  * @schema:  a schema structure
00777  *
00778  * Deallocate a RelaxNG schema structure.
00779  */
00780 static void
00781 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
00782 {
00783     if (schema == NULL)
00784         return;
00785 
00786     if (schema->doc != NULL)
00787         xmlFreeDoc(schema->doc);
00788     if (schema->defTab != NULL) {
00789         int i;
00790 
00791         for (i = 0; i < schema->defNr; i++)
00792             xmlRelaxNGFreeDefine(schema->defTab[i]);
00793         xmlFree(schema->defTab);
00794     }
00795 
00796     xmlFree(schema);
00797 }
00798 
00799 /**
00800  * xmlRelaxNGFree:
00801  * @schema:  a schema structure
00802  *
00803  * Deallocate a RelaxNG structure.
00804  */
00805 void
00806 xmlRelaxNGFree(xmlRelaxNGPtr schema)
00807 {
00808     if (schema == NULL)
00809         return;
00810 
00811     if (schema->topgrammar != NULL)
00812         xmlRelaxNGFreeGrammar(schema->topgrammar);
00813     if (schema->doc != NULL)
00814         xmlFreeDoc(schema->doc);
00815     if (schema->documents != NULL)
00816         xmlRelaxNGFreeDocumentList(schema->documents);
00817     if (schema->includes != NULL)
00818         xmlRelaxNGFreeIncludeList(schema->includes);
00819     if (schema->defTab != NULL) {
00820         int i;
00821 
00822         for (i = 0; i < schema->defNr; i++)
00823             xmlRelaxNGFreeDefine(schema->defTab[i]);
00824         xmlFree(schema->defTab);
00825     }
00826 
00827     xmlFree(schema);
00828 }
00829 
00830 /**
00831  * xmlRelaxNGNewGrammar:
00832  * @ctxt:  a Relax-NG validation context (optional)
00833  *
00834  * Allocate a new RelaxNG grammar.
00835  *
00836  * Returns the newly allocated structure or NULL in case or error
00837  */
00838 static xmlRelaxNGGrammarPtr
00839 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
00840 {
00841     xmlRelaxNGGrammarPtr ret;
00842 
00843     ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
00844     if (ret == NULL) {
00845         xmlRngPErrMemory(ctxt, NULL);
00846         return (NULL);
00847     }
00848     memset(ret, 0, sizeof(xmlRelaxNGGrammar));
00849 
00850     return (ret);
00851 }
00852 
00853 /**
00854  * xmlRelaxNGFreeGrammar:
00855  * @grammar:  a grammar structure
00856  *
00857  * Deallocate a RelaxNG grammar structure.
00858  */
00859 static void
00860 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
00861 {
00862     if (grammar == NULL)
00863         return;
00864 
00865     if (grammar->children != NULL) {
00866         xmlRelaxNGFreeGrammar(grammar->children);
00867     }
00868     if (grammar->next != NULL) {
00869         xmlRelaxNGFreeGrammar(grammar->next);
00870     }
00871     if (grammar->refs != NULL) {
00872         xmlHashFree(grammar->refs, NULL);
00873     }
00874     if (grammar->defs != NULL) {
00875         xmlHashFree(grammar->defs, NULL);
00876     }
00877 
00878     xmlFree(grammar);
00879 }
00880 
00881 /**
00882  * xmlRelaxNGNewDefine:
00883  * @ctxt:  a Relax-NG validation context
00884  * @node:  the node in the input document.
00885  *
00886  * Allocate a new RelaxNG define.
00887  *
00888  * Returns the newly allocated structure or NULL in case or error
00889  */
00890 static xmlRelaxNGDefinePtr
00891 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
00892 {
00893     xmlRelaxNGDefinePtr ret;
00894 
00895     if (ctxt->defMax == 0) {
00896         ctxt->defMax = 16;
00897         ctxt->defNr = 0;
00898         ctxt->defTab = (xmlRelaxNGDefinePtr *)
00899             xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
00900         if (ctxt->defTab == NULL) {
00901             xmlRngPErrMemory(ctxt, "allocating define\n");
00902             return (NULL);
00903         }
00904     } else if (ctxt->defMax <= ctxt->defNr) {
00905         xmlRelaxNGDefinePtr *tmp;
00906 
00907         ctxt->defMax *= 2;
00908         tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
00909                                                  ctxt->defMax *
00910                                                  sizeof
00911                                                  (xmlRelaxNGDefinePtr));
00912         if (tmp == NULL) {
00913             xmlRngPErrMemory(ctxt, "allocating define\n");
00914             return (NULL);
00915         }
00916         ctxt->defTab = tmp;
00917     }
00918     ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
00919     if (ret == NULL) {
00920         xmlRngPErrMemory(ctxt, "allocating define\n");
00921         return (NULL);
00922     }
00923     memset(ret, 0, sizeof(xmlRelaxNGDefine));
00924     ctxt->defTab[ctxt->defNr++] = ret;
00925     ret->node = node;
00926     ret->depth = -1;
00927     return (ret);
00928 }
00929 
00930 /**
00931  * xmlRelaxNGFreePartition:
00932  * @partitions:  a partition set structure
00933  *
00934  * Deallocate RelaxNG partition set structures.
00935  */
00936 static void
00937 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions)
00938 {
00939     xmlRelaxNGInterleaveGroupPtr group;
00940     int j;
00941 
00942     if (partitions != NULL) {
00943         if (partitions->groups != NULL) {
00944             for (j = 0; j < partitions->nbgroups; j++) {
00945                 group = partitions->groups[j];
00946                 if (group != NULL) {
00947                     if (group->defs != NULL)
00948                         xmlFree(group->defs);
00949                     if (group->attrs != NULL)
00950                         xmlFree(group->attrs);
00951                     xmlFree(group);
00952                 }
00953             }
00954             xmlFree(partitions->groups);
00955         }
00956         if (partitions->triage != NULL) {
00957             xmlHashFree(partitions->triage, NULL);
00958         }
00959         xmlFree(partitions);
00960     }
00961 }
00962 
00963 /**
00964  * xmlRelaxNGFreeDefine:
00965  * @define:  a define structure
00966  *
00967  * Deallocate a RelaxNG define structure.
00968  */
00969 static void
00970 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
00971 {
00972     if (define == NULL)
00973         return;
00974 
00975     if ((define->type == XML_RELAXNG_VALUE) && (define->attrs != NULL)) {
00976         xmlRelaxNGTypeLibraryPtr lib;
00977 
00978         lib = (xmlRelaxNGTypeLibraryPtr) define->data;
00979         if ((lib != NULL) && (lib->freef != NULL))
00980             lib->freef(lib->data, (void *) define->attrs);
00981     }
00982     if ((define->data != NULL) && (define->type == XML_RELAXNG_INTERLEAVE))
00983         xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
00984     if ((define->data != NULL) && (define->type == XML_RELAXNG_CHOICE))
00985         xmlHashFree((xmlHashTablePtr) define->data, NULL);
00986     if (define->name != NULL)
00987         xmlFree(define->name);
00988     if (define->ns != NULL)
00989         xmlFree(define->ns);
00990     if (define->value != NULL)
00991         xmlFree(define->value);
00992     if (define->contModel != NULL)
00993         xmlRegFreeRegexp(define->contModel);
00994     xmlFree(define);
00995 }
00996 
00997 /**
00998  * xmlRelaxNGNewStates:
00999  * @ctxt:  a Relax-NG validation context
01000  * @size:  the default size for the container
01001  *
01002  * Allocate a new RelaxNG validation state container
01003  *
01004  * Returns the newly allocated structure or NULL in case or error
01005  */
01006 static xmlRelaxNGStatesPtr
01007 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
01008 {
01009     xmlRelaxNGStatesPtr ret;
01010 
01011     if ((ctxt != NULL) &&
01012         (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
01013         ctxt->freeStatesNr--;
01014         ret = ctxt->freeStates[ctxt->freeStatesNr];
01015         ret->nbState = 0;
01016         return (ret);
01017     }
01018     if (size < 16)
01019         size = 16;
01020 
01021     ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
01022                                           (size -
01023                                            1) *
01024                                           sizeof(xmlRelaxNGValidStatePtr));
01025     if (ret == NULL) {
01026         xmlRngVErrMemory(ctxt, "allocating states\n");
01027         return (NULL);
01028     }
01029     ret->nbState = 0;
01030     ret->maxState = size;
01031     ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc((size) *
01032                                                           sizeof
01033                                                           (xmlRelaxNGValidStatePtr));
01034     if (ret->tabState == NULL) {
01035         xmlRngVErrMemory(ctxt, "allocating states\n");
01036         xmlFree(ret);
01037         return (NULL);
01038     }
01039     return (ret);
01040 }
01041 
01042 /**
01043  * xmlRelaxNGAddStateUniq:
01044  * @ctxt:  a Relax-NG validation context
01045  * @states:  the states container
01046  * @state:  the validation state
01047  *
01048  * Add a RelaxNG validation state to the container without checking
01049  * for unicity.
01050  *
01051  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
01052  */
01053 static int
01054 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
01055                         xmlRelaxNGStatesPtr states,
01056                         xmlRelaxNGValidStatePtr state)
01057 {
01058     if (state == NULL) {
01059         return (-1);
01060     }
01061     if (states->nbState >= states->maxState) {
01062         xmlRelaxNGValidStatePtr *tmp;
01063         int size;
01064 
01065         size = states->maxState * 2;
01066         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
01067                                                      (size) *
01068                                                      sizeof
01069                                                      (xmlRelaxNGValidStatePtr));
01070         if (tmp == NULL) {
01071             xmlRngVErrMemory(ctxt, "adding states\n");
01072             return (-1);
01073         }
01074         states->tabState = tmp;
01075         states->maxState = size;
01076     }
01077     states->tabState[states->nbState++] = state;
01078     return (1);
01079 }
01080 
01081 /**
01082  * xmlRelaxNGAddState:
01083  * @ctxt:  a Relax-NG validation context
01084  * @states:  the states container
01085  * @state:  the validation state
01086  *
01087  * Add a RelaxNG validation state to the container
01088  *
01089  * Return 1 in case of success and 0 if this is a duplicate and -1 on error
01090  */
01091 static int
01092 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt,
01093                     xmlRelaxNGStatesPtr states,
01094                     xmlRelaxNGValidStatePtr state)
01095 {
01096     int i;
01097 
01098     if (state == NULL || states == NULL) {
01099         return (-1);
01100     }
01101     if (states->nbState >= states->maxState) {
01102         xmlRelaxNGValidStatePtr *tmp;
01103         int size;
01104 
01105         size = states->maxState * 2;
01106         tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
01107                                                      (size) *
01108                                                      sizeof
01109                                                      (xmlRelaxNGValidStatePtr));
01110         if (tmp == NULL) {
01111             xmlRngVErrMemory(ctxt, "adding states\n");
01112             return (-1);
01113         }
01114         states->tabState = tmp;
01115         states->maxState = size;
01116     }
01117     for (i = 0; i < states->nbState; i++) {
01118         if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
01119             xmlRelaxNGFreeValidState(ctxt, state);
01120             return (0);
01121         }
01122     }
01123     states->tabState[states->nbState++] = state;
01124     return (1);
01125 }
01126 
01127 /**
01128  * xmlRelaxNGFreeStates:
01129  * @ctxt:  a Relax-NG validation context
01130  * @states:  teh container
01131  *
01132  * Free a RelaxNG validation state container
01133  */
01134 static void
01135 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
01136                      xmlRelaxNGStatesPtr states)
01137 {
01138     if (states == NULL)
01139         return;
01140     if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
01141         ctxt->freeStatesMax = 40;
01142         ctxt->freeStatesNr = 0;
01143         ctxt->freeStates = (xmlRelaxNGStatesPtr *)
01144             xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
01145         if (ctxt->freeStates == NULL) {
01146             xmlRngVErrMemory(ctxt, "storing states\n");
01147         }
01148     } else if ((ctxt != NULL)
01149                && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
01150         xmlRelaxNGStatesPtr *tmp;
01151 
01152         tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
01153                                                  2 * ctxt->freeStatesMax *
01154                                                  sizeof
01155                                                  (xmlRelaxNGStatesPtr));
01156         if (tmp == NULL) {
01157             xmlRngVErrMemory(ctxt, "storing states\n");
01158             xmlFree(states->tabState);
01159             xmlFree(states);
01160             return;
01161         }
01162         ctxt->freeStates = tmp;
01163         ctxt->freeStatesMax *= 2;
01164     }
01165     if ((ctxt == NULL) || (ctxt->freeStates == NULL)) {
01166         xmlFree(states->tabState);
01167         xmlFree(states);
01168     } else {
01169         ctxt->freeStates[ctxt->freeStatesNr++] = states;
01170     }
01171 }
01172 
01173 /**
01174  * xmlRelaxNGNewValidState:
01175  * @ctxt:  a Relax-NG validation context
01176  * @node:  the current node or NULL for the document
01177  *
01178  * Allocate a new RelaxNG validation state
01179  *
01180  * Returns the newly allocated structure or NULL in case or error
01181  */
01182 static xmlRelaxNGValidStatePtr
01183 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
01184 {
01185     xmlRelaxNGValidStatePtr ret;
01186     xmlAttrPtr attr;
01187     xmlAttrPtr attrs[MAX_ATTR];
01188     int nbAttrs = 0;
01189     xmlNodePtr root = NULL;
01190 
01191     if (node == NULL) {
01192         root = xmlDocGetRootElement(ctxt->doc);
01193         if (root == NULL)
01194             return (NULL);
01195     } else {
01196         attr = node->properties;
01197         while (attr != NULL) {
01198             if (nbAttrs < MAX_ATTR)
01199                 attrs[nbAttrs++] = attr;
01200             else
01201                 nbAttrs++;
01202             attr = attr->next;
01203         }
01204     }
01205     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
01206         ctxt->freeState->nbState--;
01207         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
01208     } else {
01209         ret =
01210             (xmlRelaxNGValidStatePtr)
01211             xmlMalloc(sizeof(xmlRelaxNGValidState));
01212         if (ret == NULL) {
01213             xmlRngVErrMemory(ctxt, "allocating states\n");
01214             return (NULL);
01215         }
01216         memset(ret, 0, sizeof(xmlRelaxNGValidState));
01217     }
01218     ret->value = NULL;
01219     ret->endvalue = NULL;
01220     if (node == NULL) {
01221         ret->node = (xmlNodePtr) ctxt->doc;
01222         ret->seq = root;
01223     } else {
01224         ret->node = node;
01225         ret->seq = node->children;
01226     }
01227     ret->nbAttrs = 0;
01228     if (nbAttrs > 0) {
01229         if (ret->attrs == NULL) {
01230             if (nbAttrs < 4)
01231                 ret->maxAttrs = 4;
01232             else
01233                 ret->maxAttrs = nbAttrs;
01234             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
01235                                                   sizeof(xmlAttrPtr));
01236             if (ret->attrs == NULL) {
01237                 xmlRngVErrMemory(ctxt, "allocating states\n");
01238                 return (ret);
01239             }
01240         } else if (ret->maxAttrs < nbAttrs) {
01241             xmlAttrPtr *tmp;
01242 
01243             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
01244                                             sizeof(xmlAttrPtr));
01245             if (tmp == NULL) {
01246                 xmlRngVErrMemory(ctxt, "allocating states\n");
01247                 return (ret);
01248             }
01249             ret->attrs = tmp;
01250             ret->maxAttrs = nbAttrs;
01251         }
01252         ret->nbAttrs = nbAttrs;
01253         if (nbAttrs < MAX_ATTR) {
01254             memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
01255         } else {
01256             attr = node->properties;
01257             nbAttrs = 0;
01258             while (attr != NULL) {
01259                 ret->attrs[nbAttrs++] = attr;
01260                 attr = attr->next;
01261             }
01262         }
01263     }
01264     ret->nbAttrLeft = ret->nbAttrs;
01265     return (ret);
01266 }
01267 
01268 /**
01269  * xmlRelaxNGCopyValidState:
01270  * @ctxt:  a Relax-NG validation context
01271  * @state:  a validation state
01272  *
01273  * Copy the validation state
01274  *
01275  * Returns the newly allocated structure or NULL in case or error
01276  */
01277 static xmlRelaxNGValidStatePtr
01278 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
01279                          xmlRelaxNGValidStatePtr state)
01280 {
01281     xmlRelaxNGValidStatePtr ret;
01282     unsigned int maxAttrs;
01283     xmlAttrPtr *attrs;
01284 
01285     if (state == NULL)
01286         return (NULL);
01287     if ((ctxt->freeState != NULL) && (ctxt->freeState->nbState > 0)) {
01288         ctxt->freeState->nbState--;
01289         ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
01290     } else {
01291         ret =
01292             (xmlRelaxNGValidStatePtr)
01293             xmlMalloc(sizeof(xmlRelaxNGValidState));
01294         if (ret == NULL) {
01295             xmlRngVErrMemory(ctxt, "allocating states\n");
01296             return (NULL);
01297         }
01298         memset(ret, 0, sizeof(xmlRelaxNGValidState));
01299     }
01300     attrs = ret->attrs;
01301     maxAttrs = ret->maxAttrs;
01302     memcpy(ret, state, sizeof(xmlRelaxNGValidState));
01303     ret->attrs = attrs;
01304     ret->maxAttrs = maxAttrs;
01305     if (state->nbAttrs > 0) {
01306         if (ret->attrs == NULL) {
01307             ret->maxAttrs = state->maxAttrs;
01308             ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
01309                                                   sizeof(xmlAttrPtr));
01310             if (ret->attrs == NULL) {
01311                 xmlRngVErrMemory(ctxt, "allocating states\n");
01312                 ret->nbAttrs = 0;
01313                 return (ret);
01314             }
01315         } else if (ret->maxAttrs < state->nbAttrs) {
01316             xmlAttrPtr *tmp;
01317 
01318             tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
01319                                             sizeof(xmlAttrPtr));
01320             if (tmp == NULL) {
01321                 xmlRngVErrMemory(ctxt, "allocating states\n");
01322                 ret->nbAttrs = 0;
01323                 return (ret);
01324             }
01325             ret->maxAttrs = state->maxAttrs;
01326             ret->attrs = tmp;
01327         }
01328         memcpy(ret->attrs, state->attrs,
01329                state->nbAttrs * sizeof(xmlAttrPtr));
01330     }
01331     return (ret);
01332 }
01333 
01334 /**
01335  * xmlRelaxNGEqualValidState:
01336  * @ctxt:  a Relax-NG validation context
01337  * @state1:  a validation state
01338  * @state2:  a validation state
01339  *
01340  * Compare the validation states for equality
01341  *
01342  * Returns 1 if equald, 0 otherwise
01343  */
01344 static int
01345 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
01346                           xmlRelaxNGValidStatePtr state1,
01347                           xmlRelaxNGValidStatePtr state2)
01348 {
01349     int i;
01350 
01351     if ((state1 == NULL) || (state2 == NULL))
01352         return (0);
01353     if (state1 == state2)
01354         return (1);
01355     if (state1->node != state2->node)
01356         return (0);
01357     if (state1->seq != state2->seq)
01358         return (0);
01359     if (state1->nbAttrLeft != state2->nbAttrLeft)
01360         return (0);
01361     if (state1->nbAttrs != state2->nbAttrs)
01362         return (0);
01363     if (state1->endvalue != state2->endvalue)
01364         return (0);
01365     if ((state1->value != state2->value) &&
01366         (!xmlStrEqual(state1->value, state2->value)))
01367         return (0);
01368     for (i = 0; i < state1->nbAttrs; i++) {
01369         if (state1->attrs[i] != state2->attrs[i])
01370             return (0);
01371     }
01372     return (1);
01373 }
01374 
01375 /**
01376  * xmlRelaxNGFreeValidState:
01377  * @state:  a validation state structure
01378  *
01379  * Deallocate a RelaxNG validation state structure.
01380  */
01381 static void
01382 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
01383                          xmlRelaxNGValidStatePtr state)
01384 {
01385     if (state == NULL)
01386         return;
01387 
01388     if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
01389         ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
01390     }
01391     if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
01392         if (state->attrs != NULL)
01393             xmlFree(state->attrs);
01394         xmlFree(state);
01395     } else {
01396         xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
01397     }
01398 }
01399 
01400 /************************************************************************
01401  *                                  *
01402  *          Semi internal functions             *
01403  *                                  *
01404  ************************************************************************/
01405 
01406 /**
01407  * xmlRelaxParserSetFlag:
01408  * @ctxt: a RelaxNG parser context
01409  * @flags: a set of flags values
01410  *
01411  * Semi private function used to pass informations to a parser context
01412  * which are a combination of xmlRelaxNGParserFlag .
01413  *
01414  * Returns 0 if success and -1 in case of error
01415  */
01416 int
01417 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt, int flags)
01418 {
01419     if (ctxt == NULL) return(-1);
01420     if (flags & XML_RELAXNGP_FREE_DOC) {
01421         ctxt->crng |= XML_RELAXNGP_FREE_DOC;
01422     flags -= XML_RELAXNGP_FREE_DOC;
01423     }
01424     if (flags & XML_RELAXNGP_CRNG) {
01425         ctxt->crng |= XML_RELAXNGP_CRNG;
01426     flags -= XML_RELAXNGP_CRNG;
01427     }
01428     if (flags != 0) return(-1);
01429     return(0);
01430 }
01431 
01432 /************************************************************************
01433  *                                  *
01434  *          Document functions              *
01435  *                                  *
01436  ************************************************************************/
01437 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
01438                                       xmlDocPtr doc);
01439 
01440 /**
01441  * xmlRelaxNGIncludePush:
01442  * @ctxt:  the parser context
01443  * @value:  the element doc
01444  *
01445  * Pushes a new include on top of the include stack
01446  *
01447  * Returns 0 in case of error, the index in the stack otherwise
01448  */
01449 static int
01450 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
01451                       xmlRelaxNGIncludePtr value)
01452 {
01453     if (ctxt->incTab == NULL) {
01454         ctxt->incMax = 4;
01455         ctxt->incNr = 0;
01456         ctxt->incTab =
01457             (xmlRelaxNGIncludePtr *) xmlMalloc(ctxt->incMax *
01458                                                sizeof(ctxt->incTab[0]));
01459         if (ctxt->incTab == NULL) {
01460             xmlRngPErrMemory(ctxt, "allocating include\n");
01461             return (0);
01462         }
01463     }
01464     if (ctxt->incNr >= ctxt->incMax) {
01465         ctxt->incMax *= 2;
01466         ctxt->incTab =
01467             (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
01468                                                 ctxt->incMax *
01469                                                 sizeof(ctxt->incTab[0]));
01470         if (ctxt->incTab == NULL) {
01471             xmlRngPErrMemory(ctxt, "allocating include\n");
01472             return (0);
01473         }
01474     }
01475     ctxt->incTab[ctxt->incNr] = value;
01476     ctxt->inc = value;
01477     return (ctxt->incNr++);
01478 }
01479 
01480 /**
01481  * xmlRelaxNGIncludePop:
01482  * @ctxt: the parser context
01483  *
01484  * Pops the top include from the include stack
01485  *
01486  * Returns the include just removed
01487  */
01488 static xmlRelaxNGIncludePtr
01489 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
01490 {
01491     xmlRelaxNGIncludePtr ret;
01492 
01493     if (ctxt->incNr <= 0)
01494         return (NULL);
01495     ctxt->incNr--;
01496     if (ctxt->incNr > 0)
01497         ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
01498     else
01499         ctxt->inc = NULL;
01500     ret = ctxt->incTab[ctxt->incNr];
01501     ctxt->incTab[ctxt->incNr] = NULL;
01502     return (ret);
01503 }
01504 
01505 /**
01506  * xmlRelaxNGRemoveRedefine:
01507  * @ctxt: the parser context
01508  * @URL:  the normalized URL
01509  * @target:  the included target
01510  * @name:  the define name to eliminate
01511  *
01512  * Applies the elimination algorithm of 4.7
01513  *
01514  * Returns 0 in case of error, 1 in case of success.
01515  */
01516 static int
01517 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
01518                          const xmlChar * URL ATTRIBUTE_UNUSED,
01519                          xmlNodePtr target, const xmlChar * name)
01520 {
01521     int found = 0;
01522     xmlNodePtr tmp, tmp2;
01523     xmlChar *name2;
01524 
01525 #ifdef DEBUG_INCLUDE
01526     if (name == NULL)
01527         xmlGenericError(xmlGenericErrorContext,
01528                         "Elimination of <include> start from %s\n", URL);
01529     else
01530         xmlGenericError(xmlGenericErrorContext,
01531                         "Elimination of <include> define %s from %s\n",
01532                         name, URL);
01533 #endif
01534     tmp = target;
01535     while (tmp != NULL) {
01536         tmp2 = tmp->next;
01537         if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
01538             found = 1;
01539             xmlUnlinkNode(tmp);
01540             xmlFreeNode(tmp);
01541         } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
01542             name2 = xmlGetProp(tmp, BAD_CAST "name");
01543             xmlRelaxNGNormExtSpace(name2);
01544             if (name2 != NULL) {
01545                 if (xmlStrEqual(name, name2)) {
01546                     found = 1;
01547                     xmlUnlinkNode(tmp);
01548                     xmlFreeNode(tmp);
01549                 }
01550                 xmlFree(name2);
01551             }
01552         } else if (IS_RELAXNG(tmp, "include")) {
01553             xmlChar *href = NULL;
01554             xmlRelaxNGDocumentPtr inc = tmp->psvi;
01555 
01556             if ((inc != NULL) && (inc->doc != NULL) &&
01557                 (inc->doc->children != NULL)) {
01558 
01559                 if (xmlStrEqual
01560                     (inc->doc->children->name, BAD_CAST "grammar")) {
01561 #ifdef DEBUG_INCLUDE
01562                     href = xmlGetProp(tmp, BAD_CAST "href");
01563 #endif
01564                     if (xmlRelaxNGRemoveRedefine(ctxt, href,
01565                                                  xmlDocGetRootElement(inc->doc)->children,
01566                                                  name) == 1) {
01567                         found = 1;
01568                     }
01569 #ifdef DEBUG_INCLUDE
01570                     if (href != NULL)
01571                         xmlFree(href);
01572 #endif
01573                 }
01574             }
01575         }
01576         tmp = tmp2;
01577     }
01578     return (found);
01579 }
01580 
01581 /**
01582  * xmlRelaxNGLoadInclude:
01583  * @ctxt: the parser context
01584  * @URL:  the normalized URL
01585  * @node: the include node.
01586  * @ns:  the namespace passed from the context.
01587  *
01588  * First lookup if the document is already loaded into the parser context,
01589  * check against recursion. If not found the resource is loaded and
01590  * the content is preprocessed before being returned back to the caller.
01591  *
01592  * Returns the xmlRelaxNGIncludePtr or NULL in case of error
01593  */
01594 static xmlRelaxNGIncludePtr
01595 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * URL,
01596                       xmlNodePtr node, const xmlChar * ns)
01597 {
01598     xmlRelaxNGIncludePtr ret = NULL;
01599     xmlDocPtr doc;
01600     int i;
01601     xmlNodePtr root, cur;
01602 
01603 #ifdef DEBUG_INCLUDE
01604     xmlGenericError(xmlGenericErrorContext,
01605                     "xmlRelaxNGLoadInclude(%s)\n", URL);
01606 #endif
01607 
01608     /*
01609      * check against recursion in the stack
01610      */
01611     for (i = 0; i < ctxt->incNr; i++) {
01612         if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
01613             xmlRngPErr(ctxt, NULL, XML_RNGP_INCLUDE_RECURSE,
01614                        "Detected an Include recursion for %s\n", URL,
01615                        NULL);
01616             return (NULL);
01617         }
01618     }
01619 
01620     /*
01621      * load the document
01622      */
01623     doc = xmlReadFile((const char *) URL,NULL,0);
01624     if (doc == NULL) {
01625         xmlRngPErr(ctxt, node, XML_RNGP_PARSE_ERROR,
01626                    "xmlRelaxNG: could not load %s\n", URL, NULL);
01627         return (NULL);
01628     }
01629 #ifdef DEBUG_INCLUDE
01630     xmlGenericError(xmlGenericErrorContext, "Parsed %s Okay\n", URL);
01631 #endif
01632 
01633     /*
01634      * Allocate the document structures and register it first.
01635      */
01636     ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
01637     if (ret == NULL) {
01638         xmlRngPErrMemory(ctxt, "allocating include\n");
01639         xmlFreeDoc(doc);
01640         return (NULL);
01641     }
01642     memset(ret, 0, sizeof(xmlRelaxNGInclude));
01643     ret->doc = doc;
01644     ret->href = xmlStrdup(URL);
01645     ret->next = ctxt->includes;
01646     ctxt->includes = ret;
01647 
01648     /*
01649      * transmit the ns if needed
01650      */
01651     if (ns != NULL) {
01652         root = xmlDocGetRootElement(doc);
01653         if (root != NULL) {
01654             if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
01655                 xmlSetProp(root, BAD_CAST "ns", ns);
01656             }
01657         }
01658     }
01659 
01660     /*
01661      * push it on the stack
01662      */
01663     xmlRelaxNGIncludePush(ctxt, ret);
01664 
01665     /*
01666      * Some preprocessing of the document content, this include recursing
01667      * in the include stack.
01668      */
01669 #ifdef DEBUG_INCLUDE
01670     xmlGenericError(xmlGenericErrorContext, "cleanup of %s\n", URL);
01671 #endif
01672 
01673     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
01674     if (doc == NULL) {
01675         ctxt->inc = NULL;
01676         return (NULL);
01677     }
01678 
01679     /*
01680      * Pop up the include from the stack
01681      */
01682     xmlRelaxNGIncludePop(ctxt);
01683 
01684 #ifdef DEBUG_INCLUDE
01685     xmlGenericError(xmlGenericErrorContext, "Checking of %s\n", URL);
01686 #endif
01687     /*
01688      * Check that the top element is a grammar
01689      */
01690     root = xmlDocGetRootElement(doc);
01691     if (root == NULL) {
01692         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY,
01693                    "xmlRelaxNG: included document is empty %s\n", URL,
01694                    NULL);
01695         return (NULL);
01696     }
01697     if (!IS_RELAXNG(root, "grammar")) {
01698         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
01699                    "xmlRelaxNG: included document %s root is not a grammar\n",
01700                    URL, NULL);
01701         return (NULL);
01702     }
01703 
01704     /*
01705      * Elimination of redefined rules in the include.
01706      */
01707     cur = node->children;
01708     while (cur != NULL) {
01709         if (IS_RELAXNG(cur, "start")) {
01710             int found = 0;
01711 
01712             found =
01713                 xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
01714             if (!found) {
01715                 xmlRngPErr(ctxt, node, XML_RNGP_START_MISSING,
01716                            "xmlRelaxNG: include %s has a start but not the included grammar\n",
01717                            URL, NULL);
01718             }
01719         } else if (IS_RELAXNG(cur, "define")) {
01720             xmlChar *name;
01721 
01722             name = xmlGetProp(cur, BAD_CAST "name");
01723             if (name == NULL) {
01724                 xmlRngPErr(ctxt, node, XML_RNGP_NAME_MISSING,
01725                            "xmlRelaxNG: include %s has define without name\n",
01726                            URL, NULL);
01727             } else {
01728                 int found;
01729 
01730                 xmlRelaxNGNormExtSpace(name);
01731                 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
01732                                                  root->children, name);
01733                 if (!found) {
01734                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_MISSING,
01735                                "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
01736                                URL, name);
01737                 }
01738                 xmlFree(name);
01739             }
01740         }
01741         cur = cur->next;
01742     }
01743 
01744 
01745     return (ret);
01746 }
01747 
01748 /**
01749  * xmlRelaxNGValidErrorPush:
01750  * @ctxt:  the validation context
01751  * @err:  the error code
01752  * @arg1:  the first string argument
01753  * @arg2:  the second string argument
01754  * @dup:  arg need to be duplicated
01755  *
01756  * Pushes a new error on top of the error stack
01757  *
01758  * Returns 0 in case of error, the index in the stack otherwise
01759  */
01760 static int
01761 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt,
01762                          xmlRelaxNGValidErr err, const xmlChar * arg1,
01763                          const xmlChar * arg2, int dup)
01764 {
01765     xmlRelaxNGValidErrorPtr cur;
01766 
01767 #ifdef DEBUG_ERROR
01768     xmlGenericError(xmlGenericErrorContext,
01769                     "Pushing error %d at %d on stack\n", err, ctxt->errNr);
01770 #endif
01771     if (ctxt->errTab == NULL) {
01772         ctxt->errMax = 8;
01773         ctxt->errNr = 0;
01774         ctxt->errTab =
01775             (xmlRelaxNGValidErrorPtr) xmlMalloc(ctxt->errMax *
01776                                                 sizeof
01777                                                 (xmlRelaxNGValidError));
01778         if (ctxt->errTab == NULL) {
01779             xmlRngVErrMemory(ctxt, "pushing error\n");
01780             return (0);
01781         }
01782         ctxt->err = NULL;
01783     }
01784     if (ctxt->errNr >= ctxt->errMax) {
01785         ctxt->errMax *= 2;
01786         ctxt->errTab =
01787             (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
01788                                                  ctxt->errMax *
01789                                                  sizeof
01790                                                  (xmlRelaxNGValidError));
01791         if (ctxt->errTab == NULL) {
01792             xmlRngVErrMemory(ctxt, "pushing error\n");
01793             return (0);
01794         }
01795         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
01796     }
01797     if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
01798         (ctxt->err->node == ctxt->state->node) && (ctxt->err->err == err))
01799         return (ctxt->errNr);
01800     cur = &ctxt->errTab[ctxt->errNr];
01801     cur->err = err;
01802     if (dup) {
01803         cur->arg1 = xmlStrdup(arg1);
01804         cur->arg2 = xmlStrdup(arg2);
01805         cur->flags = ERROR_IS_DUP;
01806     } else {
01807         cur->arg1 = arg1;
01808         cur->arg2 = arg2;
01809         cur->flags = 0;
01810     }
01811     if (ctxt->state != NULL) {
01812         cur->node = ctxt->state->node;
01813         cur->seq = ctxt->state->seq;
01814     } else {
01815         cur->node = NULL;
01816         cur->seq = NULL;
01817     }
01818     ctxt->err = cur;
01819     return (ctxt->errNr++);
01820 }
01821 
01822 /**
01823  * xmlRelaxNGValidErrorPop:
01824  * @ctxt: the validation context
01825  *
01826  * Pops the top error from the error stack
01827  */
01828 static void
01829 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
01830 {
01831     xmlRelaxNGValidErrorPtr cur;
01832 
01833     if (ctxt->errNr <= 0) {
01834         ctxt->err = NULL;
01835         return;
01836     }
01837     ctxt->errNr--;
01838     if (ctxt->errNr > 0)
01839         ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
01840     else
01841         ctxt->err = NULL;
01842     cur = &ctxt->errTab[ctxt->errNr];
01843     if (cur->flags & ERROR_IS_DUP) {
01844         if (cur->arg1 != NULL)
01845             xmlFree((xmlChar *) cur->arg1);
01846         cur->arg1 = NULL;
01847         if (cur->arg2 != NULL)
01848             xmlFree((xmlChar *) cur->arg2);
01849         cur->arg2 = NULL;
01850         cur->flags = 0;
01851     }
01852 }
01853 
01854 /**
01855  * xmlRelaxNGDocumentPush:
01856  * @ctxt:  the parser context
01857  * @value:  the element doc
01858  *
01859  * Pushes a new doc on top of the doc stack
01860  *
01861  * Returns 0 in case of error, the index in the stack otherwise
01862  */
01863 static int
01864 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
01865                        xmlRelaxNGDocumentPtr value)
01866 {
01867     if (ctxt->docTab == NULL) {
01868         ctxt->docMax = 4;
01869         ctxt->docNr = 0;
01870         ctxt->docTab =
01871             (xmlRelaxNGDocumentPtr *) xmlMalloc(ctxt->docMax *
01872                                                 sizeof(ctxt->docTab[0]));
01873         if (ctxt->docTab == NULL) {
01874             xmlRngPErrMemory(ctxt, "adding document\n");
01875             return (0);
01876         }
01877     }
01878     if (ctxt->docNr >= ctxt->docMax) {
01879         ctxt->docMax *= 2;
01880         ctxt->docTab =
01881             (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
01882                                                  ctxt->docMax *
01883                                                  sizeof(ctxt->docTab[0]));
01884         if (ctxt->docTab == NULL) {
01885             xmlRngPErrMemory(ctxt, "adding document\n");
01886             return (0);
01887         }
01888     }
01889     ctxt->docTab[ctxt->docNr] = value;
01890     ctxt->doc = value;
01891     return (ctxt->docNr++);
01892 }
01893 
01894 /**
01895  * xmlRelaxNGDocumentPop:
01896  * @ctxt: the parser context
01897  *
01898  * Pops the top doc from the doc stack
01899  *
01900  * Returns the doc just removed
01901  */
01902 static xmlRelaxNGDocumentPtr
01903 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
01904 {
01905     xmlRelaxNGDocumentPtr ret;
01906 
01907     if (ctxt->docNr <= 0)
01908         return (NULL);
01909     ctxt->docNr--;
01910     if (ctxt->docNr > 0)
01911         ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
01912     else
01913         ctxt->doc = NULL;
01914     ret = ctxt->docTab[ctxt->docNr];
01915     ctxt->docTab[ctxt->docNr] = NULL;
01916     return (ret);
01917 }
01918 
01919 /**
01920  * xmlRelaxNGLoadExternalRef:
01921  * @ctxt: the parser context
01922  * @URL:  the normalized URL
01923  * @ns:  the inherited ns if any
01924  *
01925  * First lookup if the document is already loaded into the parser context,
01926  * check against recursion. If not found the resource is loaded and
01927  * the content is preprocessed before being returned back to the caller.
01928  *
01929  * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
01930  */
01931 static xmlRelaxNGDocumentPtr
01932 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
01933                           const xmlChar * URL, const xmlChar * ns)
01934 {
01935     xmlRelaxNGDocumentPtr ret = NULL;
01936     xmlDocPtr doc;
01937     xmlNodePtr root;
01938     int i;
01939 
01940     /*
01941      * check against recursion in the stack
01942      */
01943     for (i = 0; i < ctxt->docNr; i++) {
01944         if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
01945             xmlRngPErr(ctxt, NULL, XML_RNGP_EXTERNALREF_RECURSE,
01946                        "Detected an externalRef recursion for %s\n", URL,
01947                        NULL);
01948             return (NULL);
01949         }
01950     }
01951 
01952     /*
01953      * load the document
01954      */
01955     doc = xmlReadFile((const char *) URL,NULL,0);
01956     if (doc == NULL) {
01957         xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
01958                    "xmlRelaxNG: could not load %s\n", URL, NULL);
01959         return (NULL);
01960     }
01961 
01962     /*
01963      * Allocate the document structures and register it first.
01964      */
01965     ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
01966     if (ret == NULL) {
01967         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_ERR_NO_MEMORY,
01968                    "xmlRelaxNG: allocate memory for doc %s\n", URL, NULL);
01969         xmlFreeDoc(doc);
01970         return (NULL);
01971     }
01972     memset(ret, 0, sizeof(xmlRelaxNGDocument));
01973     ret->doc = doc;
01974     ret->href = xmlStrdup(URL);
01975     ret->next = ctxt->documents;
01976     ret->externalRef = 1;
01977     ctxt->documents = ret;
01978 
01979     /*
01980      * transmit the ns if needed
01981      */
01982     if (ns != NULL) {
01983         root = xmlDocGetRootElement(doc);
01984         if (root != NULL) {
01985             if (xmlHasProp(root, BAD_CAST "ns") == NULL) {
01986                 xmlSetProp(root, BAD_CAST "ns", ns);
01987             }
01988         }
01989     }
01990 
01991     /*
01992      * push it on the stack and register it in the hash table
01993      */
01994     xmlRelaxNGDocumentPush(ctxt, ret);
01995 
01996     /*
01997      * Some preprocessing of the document content
01998      */
01999     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
02000     if (doc == NULL) {
02001         ctxt->doc = NULL;
02002         return (NULL);
02003     }
02004 
02005     xmlRelaxNGDocumentPop(ctxt);
02006 
02007     return (ret);
02008 }
02009 
02010 /************************************************************************
02011  *                                  *
02012  *          Error functions                 *
02013  *                                  *
02014  ************************************************************************/
02015 
02016 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
02017 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
02018 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
02019 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
02020 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
02021 
02022 static const char *
02023 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def)
02024 {
02025     if (def == NULL)
02026         return ("none");
02027     switch (def->type) {
02028         case XML_RELAXNG_EMPTY:
02029             return ("empty");
02030         case XML_RELAXNG_NOT_ALLOWED:
02031             return ("notAllowed");
02032         case XML_RELAXNG_EXCEPT:
02033             return ("except");
02034         case XML_RELAXNG_TEXT:
02035             return ("text");
02036         case XML_RELAXNG_ELEMENT:
02037             return ("element");
02038         case XML_RELAXNG_DATATYPE:
02039             return ("datatype");
02040         case XML_RELAXNG_VALUE:
02041             return ("value");
02042         case XML_RELAXNG_LIST:
02043             return ("list");
02044         case XML_RELAXNG_ATTRIBUTE:
02045             return ("attribute");
02046         case XML_RELAXNG_DEF:
02047             return ("def");
02048         case XML_RELAXNG_REF:
02049             return ("ref");
02050         case XML_RELAXNG_EXTERNALREF:
02051             return ("externalRef");
02052         case XML_RELAXNG_PARENTREF:
02053             return ("parentRef");
02054         case XML_RELAXNG_OPTIONAL:
02055             return ("optional");
02056         case XML_RELAXNG_ZEROORMORE:
02057             return ("zeroOrMore");
02058         case XML_RELAXNG_ONEORMORE:
02059             return ("oneOrMore");
02060         case XML_RELAXNG_CHOICE:
02061             return ("choice");
02062         case XML_RELAXNG_GROUP:
02063             return ("group");
02064         case XML_RELAXNG_INTERLEAVE:
02065             return ("interleave");
02066         case XML_RELAXNG_START:
02067             return ("start");
02068         case XML_RELAXNG_NOOP:
02069             return ("noop");
02070         case XML_RELAXNG_PARAM:
02071             return ("param");
02072     }
02073     return ("unknown");
02074 }
02075 
02076 /**
02077  * xmlRelaxNGGetErrorString:
02078  * @err:  the error code
02079  * @arg1:  the first string argument
02080  * @arg2:  the second string argument
02081  *
02082  * computes a formatted error string for the given error code and args
02083  *
02084  * Returns the error string, it must be deallocated by the caller
02085  */
02086 static xmlChar *
02087 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar * arg1,
02088                          const xmlChar * arg2)
02089 {
02090     char msg[1000];
02091 
02092     if (arg1 == NULL)
02093         arg1 = BAD_CAST "";
02094     if (arg2 == NULL)
02095         arg2 = BAD_CAST "";
02096 
02097     msg[0] = 0;
02098     switch (err) {
02099         case XML_RELAXNG_OK:
02100             return (NULL);
02101         case XML_RELAXNG_ERR_MEMORY:
02102             return (xmlCharStrdup("out of memory\n"));
02103         case XML_RELAXNG_ERR_TYPE:
02104             snprintf(msg, 1000, "failed to validate type %s\n", arg1);
02105             break;
02106         case XML_RELAXNG_ERR_TYPEVAL:
02107             snprintf(msg, 1000, "Type %s doesn't allow value '%s'\n", arg1,
02108                      arg2);
02109             break;
02110         case XML_RELAXNG_ERR_DUPID:
02111             snprintf(msg, 1000, "ID %s redefined\n", arg1);
02112             break;
02113         case XML_RELAXNG_ERR_TYPECMP:
02114             snprintf(msg, 1000, "failed to compare type %s\n", arg1);
02115             break;
02116         case XML_RELAXNG_ERR_NOSTATE:
02117             return (xmlCharStrdup("Internal error: no state\n"));
02118         case XML_RELAXNG_ERR_NODEFINE:
02119             return (xmlCharStrdup("Internal error: no define\n"));
02120         case XML_RELAXNG_ERR_INTERNAL:
02121             snprintf(msg, 1000, "Internal error: %s\n", arg1);
02122             break;
02123         case XML_RELAXNG_ERR_LISTEXTRA:
02124             snprintf(msg, 1000, "Extra data in list: %s\n", arg1);
02125             break;
02126         case XML_RELAXNG_ERR_INTERNODATA:
02127             return (xmlCharStrdup
02128                     ("Internal: interleave block has no data\n"));
02129         case XML_RELAXNG_ERR_INTERSEQ:
02130             return (xmlCharStrdup("Invalid sequence in interleave\n"));
02131         case XML_RELAXNG_ERR_INTEREXTRA:
02132             snprintf(msg, 1000, "Extra element %s in interleave\n", arg1);
02133             break;
02134         case XML_RELAXNG_ERR_ELEMNAME:
02135             snprintf(msg, 1000, "Expecting element %s, got %s\n", arg1,
02136                      arg2);
02137             break;
02138         case XML_RELAXNG_ERR_ELEMNONS:
02139             snprintf(msg, 1000, "Expecting a namespace for element %s\n",
02140                      arg1);
02141             break;
02142         case XML_RELAXNG_ERR_ELEMWRONGNS:
02143             snprintf(msg, 1000,
02144                      "Element %s has wrong namespace: expecting %s\n", arg1,
02145                      arg2);
02146             break;
02147         case XML_RELAXNG_ERR_ELEMWRONG:
02148             snprintf(msg, 1000, "Did not expect element %s there\n", arg1);
02149             break;
02150         case XML_RELAXNG_ERR_TEXTWRONG:
02151             snprintf(msg, 1000,
02152                      "Did not expect text in element %s content\n", arg1);
02153             break;
02154         case XML_RELAXNG_ERR_ELEMEXTRANS:
02155             snprintf(msg, 1000, "Expecting no namespace for element %s\n",
02156                      arg1);
02157             break;
02158         case XML_RELAXNG_ERR_ELEMNOTEMPTY:
02159             snprintf(msg, 1000, "Expecting element %s to be empty\n", arg1);
02160             break;
02161         case XML_RELAXNG_ERR_NOELEM:
02162             snprintf(msg, 1000, "Expecting an element %s, got nothing\n",
02163                      arg1);
02164             break;
02165         case XML_RELAXNG_ERR_NOTELEM:
02166             return (xmlCharStrdup("Expecting an element got text\n"));
02167         case XML_RELAXNG_ERR_ATTRVALID:
02168             snprintf(msg, 1000, "Element %s failed to validate attributes\n",
02169                      arg1);
02170             break;
02171         case XML_RELAXNG_ERR_CONTENTVALID:
02172             snprintf(msg, 1000, "Element %s failed to validate content\n",
02173                      arg1);
02174             break;
02175         case XML_RELAXNG_ERR_EXTRACONTENT:
02176             snprintf(msg, 1000, "Element %s has extra content: %s\n",
02177                      arg1, arg2);
02178             break;
02179         case XML_RELAXNG_ERR_INVALIDATTR:
02180             snprintf(msg, 1000, "Invalid attribute %s for element %s\n",
02181                      arg1, arg2);
02182             break;
02183         case XML_RELAXNG_ERR_LACKDATA:
02184             snprintf(msg, 1000, "Datatype element %s contains no data\n",
02185                      arg1);
02186             break;
02187         case XML_RELAXNG_ERR_DATAELEM:
02188             snprintf(msg, 1000, "Datatype element %s has child elements\n",
02189                      arg1);
02190             break;
02191         case XML_RELAXNG_ERR_VALELEM:
02192             snprintf(msg, 1000, "Value element %s has child elements\n",
02193                      arg1);
02194             break;
02195         case XML_RELAXNG_ERR_LISTELEM:
02196             snprintf(msg, 1000, "List element %s has child elements\n",
02197                      arg1);
02198             break;
02199         case XML_RELAXNG_ERR_DATATYPE:
02200             snprintf(msg, 1000, "Error validating datatype %s\n", arg1);
02201             break;
02202         case XML_RELAXNG_ERR_VALUE:
02203             snprintf(msg, 1000, "Error validating value %s\n", arg1);
02204             break;
02205         case XML_RELAXNG_ERR_LIST:
02206             return (xmlCharStrdup("Error validating list\n"));
02207         case XML_RELAXNG_ERR_NOGRAMMAR:
02208             return (xmlCharStrdup("No top grammar defined\n"));
02209         case XML_RELAXNG_ERR_EXTRADATA:
02210             return (xmlCharStrdup("Extra data in the document\n"));
02211         default:
02212             return (xmlCharStrdup("Unknown error !\n"));
02213     }
02214     if (msg[0] == 0) {
02215         snprintf(msg, 1000, "Unknown error code %d\n", err);
02216     }
02217     msg[1000 - 1] = 0;
02218     return (xmlStrdup((xmlChar *) msg));
02219 }
02220 
02221 /**
02222  * xmlRelaxNGShowValidError:
02223  * @ctxt:  the validation context
02224  * @err:  the error number
02225  * @node:  the node
02226  * @child:  the node child generating the problem.
02227  * @arg1:  the first argument
02228  * @arg2:  the second argument
02229  *
02230  * Show a validation error.
02231  */
02232 static void
02233 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt,
02234                          xmlRelaxNGValidErr err, xmlNodePtr node,
02235                          xmlNodePtr child, const xmlChar * arg1,
02236                          const xmlChar * arg2)
02237 {
02238     xmlChar *msg;
02239 
02240     if (ctxt->flags & FLAGS_NOERROR)
02241         return;
02242 
02243 #ifdef DEBUG_ERROR
02244     xmlGenericError(xmlGenericErrorContext, "Show error %d\n", err);
02245 #endif
02246     msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
02247     if (msg == NULL)
02248         return;
02249 
02250     if (ctxt->errNo == XML_RELAXNG_OK)
02251         ctxt->errNo = err;
02252     xmlRngVErr(ctxt, (child == NULL ? node : child), err,
02253                (const char *) msg, arg1, arg2);
02254     xmlFree(msg);
02255 }
02256 
02257 /**
02258  * xmlRelaxNGPopErrors:
02259  * @ctxt:  the validation context
02260  * @level:  the error level in the stack
02261  *
02262  * pop and discard all errors until the given level is reached
02263  */
02264 static void
02265 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level)
02266 {
02267     int i;
02268     xmlRelaxNGValidErrorPtr err;
02269 
02270 #ifdef DEBUG_ERROR
02271     xmlGenericError(xmlGenericErrorContext,
02272                     "Pop errors till level %d\n", level);
02273 #endif
02274     for (i = level; i < ctxt->errNr; i++) {
02275         err = &ctxt->errTab[i];
02276         if (err->flags & ERROR_IS_DUP) {
02277             if (err->arg1 != NULL)
02278                 xmlFree((xmlChar *) err->arg1);
02279             err->arg1 = NULL;
02280             if (err->arg2 != NULL)
02281                 xmlFree((xmlChar *) err->arg2);
02282             err->arg2 = NULL;
02283             err->flags = 0;
02284         }
02285     }
02286     ctxt->errNr = level;
02287     if (ctxt->errNr <= 0)
02288         ctxt->err = NULL;
02289 }
02290 
02291 /**
02292  * xmlRelaxNGDumpValidError:
02293  * @ctxt:  the validation context
02294  *
02295  * Show all validation error over a given index.
02296  */
02297 static void
02298 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt)
02299 {
02300     int i, j, k;
02301     xmlRelaxNGValidErrorPtr err, dup;
02302 
02303 #ifdef DEBUG_ERROR
02304     xmlGenericError(xmlGenericErrorContext,
02305                     "Dumping error stack %d errors\n", ctxt->errNr);
02306 #endif
02307     for (i = 0, k = 0; i < ctxt->errNr; i++) {
02308         err = &ctxt->errTab[i];
02309         if (k < MAX_ERROR) {
02310             for (j = 0; j < i; j++) {
02311                 dup = &ctxt->errTab[j];
02312                 if ((err->err == dup->err) && (err->node == dup->node) &&
02313                     (xmlStrEqual(err->arg1, dup->arg1)) &&
02314                     (xmlStrEqual(err->arg2, dup->arg2))) {
02315                     goto skip;
02316                 }
02317             }
02318             xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
02319                                      err->arg1, err->arg2);
02320             k++;
02321         }
02322       skip:
02323         if (err->flags & ERROR_IS_DUP) {
02324             if (err->arg1 != NULL)
02325                 xmlFree((xmlChar *) err->arg1);
02326             err->arg1 = NULL;
02327             if (err->arg2 != NULL)
02328                 xmlFree((xmlChar *) err->arg2);
02329             err->arg2 = NULL;
02330             err->flags = 0;
02331         }
02332     }
02333     ctxt->errNr = 0;
02334 }
02335 
02336 /**
02337  * xmlRelaxNGAddValidError:
02338  * @ctxt:  the validation context
02339  * @err:  the error number
02340  * @arg1:  the first argument
02341  * @arg2:  the second argument
02342  * @dup:  need to dup the args
02343  *
02344  * Register a validation error, either generating it if it's sure
02345  * or stacking it for later handling if unsure.
02346  */
02347 static void
02348 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
02349                         xmlRelaxNGValidErr err, const xmlChar * arg1,
02350                         const xmlChar * arg2, int dup)
02351 {
02352     if (ctxt == NULL)
02353         return;
02354     if (ctxt->flags & FLAGS_NOERROR)
02355         return;
02356 
02357 #ifdef DEBUG_ERROR
02358     xmlGenericError(xmlGenericErrorContext, "Adding error %d\n", err);
02359 #endif
02360     /*
02361      * generate the error directly
02362      */
02363     if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
02364      (ctxt->flags & FLAGS_NEGATIVE)) {
02365         xmlNodePtr node, seq;
02366 
02367         /*
02368          * Flush first any stacked error which might be the
02369          * real cause of the problem.
02370          */
02371         if (ctxt->errNr != 0)
02372             xmlRelaxNGDumpValidError(ctxt);
02373         if (ctxt->state != NULL) {
02374             node = ctxt->state->node;
02375             seq = ctxt->state->seq;
02376         } else {
02377             node = seq = NULL;
02378         }
02379         if ((node == NULL) && (seq == NULL)) {
02380             node = ctxt->pnode;
02381         }
02382         xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
02383     }
02384     /*
02385      * Stack the error for later processing if needed
02386      */
02387     else {
02388         xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
02389     }
02390 }
02391 
02392 
02393 /************************************************************************
02394  *                                  *
02395  *          Type library hooks              *
02396  *                                  *
02397  ************************************************************************/
02398 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
02399                                     const xmlChar * str);
02400 
02401 /**
02402  * xmlRelaxNGSchemaTypeHave:
02403  * @data:  data needed for the library
02404  * @type:  the type name
02405  *
02406  * Check if the given type is provided by
02407  * the W3C XMLSchema Datatype library.
02408  *
02409  * Returns 1 if yes, 0 if no and -1 in case of error.
02410  */
02411 static int
02412 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar * type)
02413 {
02414     xmlSchemaTypePtr typ;
02415 
02416     if (type == NULL)
02417         return (-1);
02418     typ = xmlSchemaGetPredefinedType(type,
02419                                      BAD_CAST
02420                                      "http://www.w3.org/2001/XMLSchema");
02421     if (typ == NULL)
02422         return (0);
02423     return (1);
02424 }
02425 
02426 /**
02427  * xmlRelaxNGSchemaTypeCheck:
02428  * @data:  data needed for the library
02429  * @type:  the type name
02430  * @value:  the value to check
02431  * @node:  the node
02432  *
02433  * Check if the given type and value are validated by
02434  * the W3C XMLSchema Datatype library.
02435  *
02436  * Returns 1 if yes, 0 if no and -1 in case of error.
02437  */
02438 static int
02439 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
02440                           const xmlChar * type,
02441                           const xmlChar * value,
02442                           void **result, xmlNodePtr node)
02443 {
02444     xmlSchemaTypePtr typ;
02445     int ret;
02446 
02447     if ((type == NULL) || (value == NULL))
02448         return (-1);
02449     typ = xmlSchemaGetPredefinedType(type,
02450                                      BAD_CAST
02451                                      "http://www.w3.org/2001/XMLSchema");
02452     if (typ == NULL)
02453         return (-1);
02454     ret = xmlSchemaValPredefTypeNode(typ, value,
02455                                      (xmlSchemaValPtr *) result, node);
02456     if (ret == 2)               /* special ID error code */
02457         return (2);
02458     if (ret == 0)
02459         return (1);
02460     if (ret > 0)
02461         return (0);
02462     return (-1);
02463 }
02464 
02465 /**
02466  * xmlRelaxNGSchemaFacetCheck:
02467  * @data:  data needed for the library
02468  * @type:  the type name
02469  * @facet:  the facet name
02470  * @val:  the facet value
02471  * @strval:  the string value
02472  * @value:  the value to check
02473  *
02474  * Function provided by a type library to check a value facet
02475  *
02476  * Returns 1 if yes, 0 if no and -1 in case of error.
02477  */
02478 static int
02479 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED,
02480                            const xmlChar * type, const xmlChar * facetname,
02481                            const xmlChar * val, const xmlChar * strval,
02482                            void *value)
02483 {
02484     xmlSchemaFacetPtr facet;
02485     xmlSchemaTypePtr typ;
02486     int ret;
02487 
02488     if ((type == NULL) || (strval == NULL))
02489         return (-1);
02490     typ = xmlSchemaGetPredefinedType(type,
02491                                      BAD_CAST
02492                                      "http://www.w3.org/2001/XMLSchema");
02493     if (typ == NULL)
02494         return (-1);
02495 
02496     facet = xmlSchemaNewFacet();
02497     if (facet == NULL)
02498         return (-1);
02499 
02500     if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
02501         facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
02502     } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
02503         facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
02504     } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
02505         facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
02506     } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
02507         facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
02508     } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
02509         facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
02510     } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
02511         facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
02512     } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
02513         facet->type = XML_SCHEMA_FACET_PATTERN;
02514     } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
02515         facet->type = XML_SCHEMA_FACET_ENUMERATION;
02516     } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
02517         facet->type = XML_SCHEMA_FACET_WHITESPACE;
02518     } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
02519         facet->type = XML_SCHEMA_FACET_LENGTH;
02520     } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
02521         facet->type = XML_SCHEMA_FACET_MAXLENGTH;
02522     } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
02523         facet->type = XML_SCHEMA_FACET_MINLENGTH;
02524     } else {
02525         xmlSchemaFreeFacet(facet);
02526         return (-1);
02527     }
02528     facet->value = val;
02529     ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
02530     if (ret != 0) {
02531         xmlSchemaFreeFacet(facet);
02532         return (-1);
02533     }
02534     ret = xmlSchemaValidateFacet(typ, facet, strval, value);
02535     xmlSchemaFreeFacet(facet);
02536     if (ret != 0)
02537         return (-1);
02538     return (0);
02539 }
02540 
02541 /**
02542  * xmlRelaxNGSchemaFreeValue:
02543  * @data:  data needed for the library
02544  * @value:  the value to free
02545  *
02546  * Function provided by a type library to free a Schemas value
02547  *
02548  * Returns 1 if yes, 0 if no and -1 in case of error.
02549  */
02550 static void
02551 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED, void *value)
02552 {
02553     xmlSchemaFreeValue(value);
02554 }
02555 
02556 /**
02557  * xmlRelaxNGSchemaTypeCompare:
02558  * @data:  data needed for the library
02559  * @type:  the type name
02560  * @value1:  the first value
02561  * @value2:  the second value
02562  *
02563  * Compare two values for equality accordingly a type from the W3C XMLSchema
02564  * Datatype library.
02565  *
02566  * Returns 1 if equal, 0 if no and -1 in case of error.
02567  */
02568 static int
02569 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
02570                             const xmlChar * type,
02571                             const xmlChar * value1,
02572                             xmlNodePtr ctxt1,
02573                             void *comp1,
02574                             const xmlChar * value2, xmlNodePtr ctxt2)
02575 {
02576     int ret;
02577     xmlSchemaTypePtr typ;
02578     xmlSchemaValPtr res1 = NULL, res2 = NULL;
02579 
02580     if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
02581         return (-1);
02582     typ = xmlSchemaGetPredefinedType(type,
02583                                      BAD_CAST
02584                                      "http://www.w3.org/2001/XMLSchema");
02585     if (typ == NULL)
02586         return (-1);
02587     if (comp1 == NULL) {
02588         ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
02589         if (ret != 0)
02590             return (-1);
02591         if (res1 == NULL)
02592             return (-1);
02593     } else {
02594         res1 = (xmlSchemaValPtr) comp1;
02595     }
02596     ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
02597     if (ret != 0) {
02598     if (res1 != (xmlSchemaValPtr) comp1)
02599         xmlSchemaFreeValue(res1);
02600         return (-1);
02601     }
02602     ret = xmlSchemaCompareValues(res1, res2);
02603     if (res1 != (xmlSchemaValPtr) comp1)
02604         xmlSchemaFreeValue(res1);
02605     xmlSchemaFreeValue(res2);
02606     if (ret == -2)
02607         return (-1);
02608     if (ret == 0)
02609         return (1);
02610     return (0);
02611 }
02612 
02613 /**
02614  * xmlRelaxNGDefaultTypeHave:
02615  * @data:  data needed for the library
02616  * @type:  the type name
02617  *
02618  * Check if the given type is provided by
02619  * the default datatype library.
02620  *
02621  * Returns 1 if yes, 0 if no and -1 in case of error.
02622  */
02623 static int
02624 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED,
02625                           const xmlChar * type)
02626 {
02627     if (type == NULL)
02628         return (-1);
02629     if (xmlStrEqual(type, BAD_CAST "string"))
02630         return (1);
02631     if (xmlStrEqual(type, BAD_CAST "token"))
02632         return (1);
02633     return (0);
02634 }
02635 
02636 /**
02637  * xmlRelaxNGDefaultTypeCheck:
02638  * @data:  data needed for the library
02639  * @type:  the type name
02640  * @value:  the value to check
02641  * @node:  the node
02642  *
02643  * Check if the given type and value are validated by
02644  * the default datatype library.
02645  *
02646  * Returns 1 if yes, 0 if no and -1 in case of error.
02647  */
02648 static int
02649 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
02650                            const xmlChar * type ATTRIBUTE_UNUSED,
02651                            const xmlChar * value ATTRIBUTE_UNUSED,
02652                            void **result ATTRIBUTE_UNUSED,
02653                            xmlNodePtr node ATTRIBUTE_UNUSED)
02654 {
02655     if (value == NULL)
02656         return (-1);
02657     if (xmlStrEqual(type, BAD_CAST "string"))
02658         return (1);
02659     if (xmlStrEqual(type, BAD_CAST "token")) {
02660         return (1);
02661     }
02662 
02663     return (0);
02664 }
02665 
02666 /**
02667  * xmlRelaxNGDefaultTypeCompare:
02668  * @data:  data needed for the library
02669  * @type:  the type name
02670  * @value1:  the first value
02671  * @value2:  the second value
02672  *
02673  * Compare two values accordingly a type from the default
02674  * datatype library.
02675  *
02676  * Returns 1 if yes, 0 if no and -1 in case of error.
02677  */
02678 static int
02679 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
02680                              const xmlChar * type,
02681                              const xmlChar * value1,
02682                              xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
02683                              void *comp1 ATTRIBUTE_UNUSED,
02684                              const xmlChar * value2,
02685                              xmlNodePtr ctxt2 ATTRIBUTE_UNUSED)
02686 {
02687     int ret = -1;
02688 
02689     if (xmlStrEqual(type, BAD_CAST "string")) {
02690         ret = xmlStrEqual(value1, value2);
02691     } else if (xmlStrEqual(type, BAD_CAST "token")) {
02692         if (!xmlStrEqual(value1, value2)) {
02693             xmlChar *nval, *nvalue;
02694 
02695             /*
02696              * TODO: trivial optimizations are possible by
02697              * computing at compile-time
02698              */
02699             nval = xmlRelaxNGNormalize(NULL, value1);
02700             nvalue = xmlRelaxNGNormalize(NULL, value2);
02701 
02702             if ((nval == NULL) || (nvalue == NULL))
02703                 ret = -1;
02704             else if (xmlStrEqual(nval, nvalue))
02705                 ret = 1;
02706             else
02707                 ret = 0;
02708             if (nval != NULL)
02709                 xmlFree(nval);
02710             if (nvalue != NULL)
02711                 xmlFree(nvalue);
02712         } else
02713             ret = 1;
02714     }
02715     return (ret);
02716 }
02717 
02718 static int xmlRelaxNGTypeInitialized = 0;
02719 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
02720 
02721 /**
02722  * xmlRelaxNGFreeTypeLibrary:
02723  * @lib:  the type library structure
02724  * @namespace:  the URI bound to the library
02725  *
02726  * Free the structure associated to the type library
02727  */
02728 static void
02729 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
02730                           const xmlChar * namespace ATTRIBUTE_UNUSED)
02731 {
02732     if (lib == NULL)
02733         return;
02734     if (lib->namespace != NULL)
02735         xmlFree((xmlChar *) lib->namespace);
02736     xmlFree(lib);
02737 }
02738 
02739 /**
02740  * xmlRelaxNGRegisterTypeLibrary:
02741  * @namespace:  the URI bound to the library
02742  * @data:  data associated to the library
02743  * @have:  the provide function
02744  * @check:  the checking function
02745  * @comp:  the comparison function
02746  *
02747  * Register a new type library
02748  *
02749  * Returns 0 in case of success and -1 in case of error.
02750  */
02751 static int
02752 xmlRelaxNGRegisterTypeLibrary(const xmlChar * namespace, void *data,
02753                               xmlRelaxNGTypeHave have,
02754                               xmlRelaxNGTypeCheck check,
02755                               xmlRelaxNGTypeCompare comp,
02756                               xmlRelaxNGFacetCheck facet,
02757                               xmlRelaxNGTypeFree freef)
02758 {
02759     xmlRelaxNGTypeLibraryPtr lib;
02760     int ret;
02761 
02762     if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
02763         (check == NULL) || (comp == NULL))
02764         return (-1);
02765     if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
02766         xmlGenericError(xmlGenericErrorContext,
02767                         "Relax-NG types library '%s' already registered\n",
02768                         namespace);
02769         return (-1);
02770     }
02771     lib =
02772         (xmlRelaxNGTypeLibraryPtr)
02773         xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
02774     if (lib == NULL) {
02775         xmlRngVErrMemory(NULL, "adding types library\n");
02776         return (-1);
02777     }
02778     memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
02779     lib->namespace = xmlStrdup(namespace);
02780     lib->data = data;
02781     lib->have = have;
02782     lib->comp = comp;
02783     lib->check = check;
02784     lib->facet = facet;
02785     lib->freef = freef;
02786     ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
02787     if (ret < 0) {
02788         xmlGenericError(xmlGenericErrorContext,
02789                         "Relax-NG types library failed to register '%s'\n",
02790                         namespace);
02791         xmlRelaxNGFreeTypeLibrary(lib, namespace);
02792         return (-1);
02793     }
02794     return (0);
02795 }
02796 
02797 /**
02798  * xmlRelaxNGInitTypes:
02799  *
02800  * Initilize the default type libraries.
02801  *
02802  * Returns 0 in case of success and -1 in case of error.
02803  */
02804 int
02805 xmlRelaxNGInitTypes(void)
02806 {
02807     if (xmlRelaxNGTypeInitialized != 0)
02808         return (0);
02809     xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
02810     if (xmlRelaxNGRegisteredTypes == NULL) {
02811         xmlGenericError(xmlGenericErrorContext,
02812                         "Failed to allocate sh table for Relax-NG types\n");
02813         return (-1);
02814     }
02815     xmlRelaxNGRegisterTypeLibrary(BAD_CAST
02816                                   "http://www.w3.org/2001/XMLSchema-datatypes",
02817                                   NULL, xmlRelaxNGSchemaTypeHave,
02818                                   xmlRelaxNGSchemaTypeCheck,
02819                                   xmlRelaxNGSchemaTypeCompare,
02820                                   xmlRelaxNGSchemaFacetCheck,
02821                                   xmlRelaxNGSchemaFreeValue);
02822     xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs, NULL,
02823                                   xmlRelaxNGDefaultTypeHave,
02824                                   xmlRelaxNGDefaultTypeCheck,
02825                                   xmlRelaxNGDefaultTypeCompare, NULL,
02826                                   NULL);
02827     xmlRelaxNGTypeInitialized = 1;
02828     return (0);
02829 }
02830 
02831 /**
02832  * xmlRelaxNGCleanupTypes:
02833  *
02834  * Cleanup the default Schemas type library associated to RelaxNG
02835  */
02836 void
02837 xmlRelaxNGCleanupTypes(void)
02838 {
02839     xmlSchemaCleanupTypes();
02840     if (xmlRelaxNGTypeInitialized == 0)
02841         return;
02842     xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
02843                 xmlRelaxNGFreeTypeLibrary);
02844     xmlRelaxNGTypeInitialized = 0;
02845 }
02846 
02847 /************************************************************************
02848  *                                  *
02849  *      Compiling element content into regexp           *
02850  *                                  *
02851  * Sometime the element content can be compiled into a pure regexp, *
02852  * This allows a faster execution and streamability at that level   *
02853  *                                  *
02854  ************************************************************************/
02855 
02856 /* from automata.c but not exported */
02857 void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
02858 
02859 
02860 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
02861                                 xmlRelaxNGDefinePtr def);
02862 
02863 /**
02864  * xmlRelaxNGIsCompileable:
02865  * @define:  the definition to check
02866  *
02867  * Check if a definition is nullable.
02868  *
02869  * Returns 1 if yes, 0 if no and -1 in case of error
02870  */
02871 static int
02872 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def)
02873 {
02874     int ret = -1;
02875 
02876     if (def == NULL) {
02877         return (-1);
02878     }
02879     if ((def->type != XML_RELAXNG_ELEMENT) &&
02880         (def->dflags & IS_COMPILABLE))
02881         return (1);
02882     if ((def->type != XML_RELAXNG_ELEMENT) &&
02883         (def->dflags & IS_NOT_COMPILABLE))
02884         return (0);
02885     switch (def->type) {
02886         case XML_RELAXNG_NOOP:
02887             ret = xmlRelaxNGIsCompileable(def->content);
02888             break;
02889         case XML_RELAXNG_TEXT:
02890         case XML_RELAXNG_EMPTY:
02891             ret = 1;
02892             break;
02893         case XML_RELAXNG_ELEMENT:
02894             /*
02895              * Check if the element content is compileable
02896              */
02897             if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
02898                 ((def->dflags & IS_COMPILABLE) == 0)) {
02899                 xmlRelaxNGDefinePtr list;
02900 
02901                 list = def->content;
02902                 while (list != NULL) {
02903                     ret = xmlRelaxNGIsCompileable(list);
02904                     if (ret != 1)
02905                         break;
02906                     list = list->next;
02907                 }
02908         /*
02909          * Because the routine is recursive, we must guard against
02910          * discovering both COMPILABLE and NOT_COMPILABLE
02911          */
02912                 if (ret == 0) {
02913             def->dflags &= ~IS_COMPILABLE;
02914                     def->dflags |= IS_NOT_COMPILABLE;
02915         }
02916                 if ((ret == 1) && !(def->dflags &= IS_NOT_COMPILABLE))
02917                     def->dflags |= IS_COMPILABLE;
02918 #ifdef DEBUG_COMPILE
02919                 if (ret == 1) {
02920                     xmlGenericError(xmlGenericErrorContext,
02921                                     "element content for %s is compilable\n",
02922                                     def->name);
02923                 } else if (ret == 0) {
02924                     xmlGenericError(xmlGenericErrorContext,
02925                                     "element content for %s is not compilable\n",
02926                                     def->name);
02927                 } else {
02928                     xmlGenericError(xmlGenericErrorContext,
02929                                     "Problem in RelaxNGIsCompileable for element %s\n",
02930                                     def->name);
02931                 }
02932 #endif
02933             }
02934             /*
02935              * All elements return a compileable status unless they
02936              * are generic like anyName
02937              */
02938             if ((def->nameClass != NULL) || (def->name == NULL))
02939                 ret = 0;
02940             else
02941                 ret = 1;
02942             return (ret);
02943         case XML_RELAXNG_REF:
02944         case XML_RELAXNG_EXTERNALREF:
02945         case XML_RELAXNG_PARENTREF:
02946             if (def->depth == -20) {
02947                 return (1);
02948             } else {
02949                 xmlRelaxNGDefinePtr list;
02950 
02951                 def->depth = -20;
02952                 list = def->content;
02953                 while (list != NULL) {
02954                     ret = xmlRelaxNGIsCompileable(list);
02955                     if (ret != 1)
02956                         break;
02957                     list = list->next;
02958                 }
02959             }
02960             break;
02961         case XML_RELAXNG_START:
02962         case XML_RELAXNG_OPTIONAL:
02963         case XML_RELAXNG_ZEROORMORE:
02964         case XML_RELAXNG_ONEORMORE:
02965         case XML_RELAXNG_CHOICE:
02966         case XML_RELAXNG_GROUP:
02967         case XML_RELAXNG_DEF:{
02968                 xmlRelaxNGDefinePtr list;
02969 
02970                 list = def->content;
02971                 while (list != NULL) {
02972                     ret = xmlRelaxNGIsCompileable(list);
02973                     if (ret != 1)
02974                         break;
02975                     list = list->next;
02976                 }
02977                 break;
02978             }
02979         case XML_RELAXNG_EXCEPT:
02980         case XML_RELAXNG_ATTRIBUTE:
02981         case XML_RELAXNG_INTERLEAVE:
02982         case XML_RELAXNG_DATATYPE:
02983         case XML_RELAXNG_LIST:
02984         case XML_RELAXNG_PARAM:
02985         case XML_RELAXNG_VALUE:
02986         case XML_RELAXNG_NOT_ALLOWED:
02987             ret = 0;
02988             break;
02989     }
02990     if (ret == 0)
02991         def->dflags |= IS_NOT_COMPILABLE;
02992     if (ret == 1)
02993         def->dflags |= IS_COMPILABLE;
02994 #ifdef DEBUG_COMPILE
02995     if (ret == 1) {
02996         xmlGenericError(xmlGenericErrorContext,
02997                         "RelaxNGIsCompileable %s : true\n",
02998                         xmlRelaxNGDefName(def));
02999     } else if (ret == 0) {
03000         xmlGenericError(xmlGenericErrorContext,
03001                         "RelaxNGIsCompileable %s : false\n",
03002                         xmlRelaxNGDefName(def));
03003     } else {
03004         xmlGenericError(xmlGenericErrorContext,
03005                         "Problem in RelaxNGIsCompileable %s\n",
03006                         xmlRelaxNGDefName(def));
03007     }
03008 #endif
03009     return (ret);
03010 }
03011 
03012 /**
03013  * xmlRelaxNGCompile:
03014  * ctxt:  the RelaxNG parser context
03015  * @define:  the definition tree to compile
03016  *
03017  * Compile the set of definitions, it works recursively, till the
03018  * element boundaries, where it tries to compile the content if possible
03019  *
03020  * Returns 0 if success and -1 in case of error
03021  */
03022 static int
03023 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
03024 {
03025     int ret = 0;
03026     xmlRelaxNGDefinePtr list;
03027 
03028     if ((ctxt == NULL) || (def == NULL))
03029         return (-1);
03030 
03031     switch (def->type) {
03032         case XML_RELAXNG_START:
03033             if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
03034                 xmlAutomataPtr oldam = ctxt->am;
03035                 xmlAutomataStatePtr oldstate = ctxt->state;
03036 
03037                 def->depth = -25;
03038 
03039                 list = def->content;
03040                 ctxt->am = xmlNewAutomata();
03041                 if (ctxt->am == NULL)
03042                     return (-1);
03043 
03044                 /*
03045                  * assume identical strings but not same pointer are different
03046                  * atoms, needed for non-determinism detection
03047                  * That way if 2 elements with the same name are in a choice
03048                  * branch the automata is found non-deterministic and
03049                  * we fallback to the normal validation which does the right
03050                  * thing of exploring both choices.
03051                  */
03052                 xmlAutomataSetFlags(ctxt->am, 1);
03053 
03054                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
03055                 while (list != NULL) {
03056                     xmlRelaxNGCompile(ctxt, list);
03057                     list = list->next;
03058                 }
03059                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
03060                 if (xmlAutomataIsDeterminist(ctxt->am))
03061                     def->contModel = xmlAutomataCompile(ctxt->am);
03062 
03063                 xmlFreeAutomata(ctxt->am);
03064                 ctxt->state = oldstate;
03065                 ctxt->am = oldam;
03066             }
03067             break;
03068         case XML_RELAXNG_ELEMENT:
03069             if ((ctxt->am != NULL) && (def->name != NULL)) {
03070                 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
03071                                                         ctxt->state, NULL,
03072                                                         def->name, def->ns,
03073                                                         def);
03074             }
03075             if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
03076                 xmlAutomataPtr oldam = ctxt->am;
03077                 xmlAutomataStatePtr oldstate = ctxt->state;
03078 
03079                 def->depth = -25;
03080 
03081                 list = def->content;
03082                 ctxt->am = xmlNewAutomata();
03083                 if (ctxt->am == NULL)
03084                     return (-1);
03085                 xmlAutomataSetFlags(ctxt->am, 1);
03086                 ctxt->state = xmlAutomataGetInitState(ctxt->am);
03087                 while (list != NULL) {
03088                     xmlRelaxNGCompile(ctxt, list);
03089                     list = list->next;
03090                 }
03091                 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
03092                 def->contModel = xmlAutomataCompile(ctxt->am);
03093                 if (!xmlRegexpIsDeterminist(def->contModel)) {
03094 #ifdef DEBUG_COMPILE
03095                     xmlGenericError(xmlGenericErrorContext,
03096                         "Content model not determinist %s\n",
03097                                     def->name);
03098 #endif
03099                     /*
03100                      * we can only use the automata if it is determinist
03101                      */
03102                     xmlRegFreeRegexp(def->contModel);
03103                     def->contModel = NULL;
03104                 }
03105                 xmlFreeAutomata(ctxt->am);
03106                 ctxt->state = oldstate;
03107                 ctxt->am = oldam;
03108             } else {
03109                 xmlAutomataPtr oldam = ctxt->am;
03110 
03111                 /*
03112                  * we can't build the content model for this element content
03113                  * but it still might be possible to build it for some of its
03114                  * children, recurse.
03115                  */
03116                 ret = xmlRelaxNGTryCompile(ctxt, def);
03117                 ctxt->am = oldam;
03118             }
03119             break;
03120         case XML_RELAXNG_NOOP:
03121             ret = xmlRelaxNGCompile(ctxt, def->content);
03122             break;
03123         case XML_RELAXNG_OPTIONAL:{
03124                 xmlAutomataStatePtr oldstate = ctxt->state;
03125 
03126                 list = def->content;
03127                 while (list != NULL) {
03128                     xmlRelaxNGCompile(ctxt, list);
03129                     list = list->next;
03130                 }
03131                 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
03132                 break;
03133             }
03134         case XML_RELAXNG_ZEROORMORE:{
03135                 xmlAutomataStatePtr oldstate;
03136 
03137                 ctxt->state =
03138                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
03139                 oldstate = ctxt->state;
03140                 list = def->content;
03141                 while (list != NULL) {
03142                     xmlRelaxNGCompile(ctxt, list);
03143                     list = list->next;
03144                 }
03145                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
03146                 ctxt->state =
03147                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
03148                 break;
03149             }
03150         case XML_RELAXNG_ONEORMORE:{
03151                 xmlAutomataStatePtr oldstate;
03152 
03153                 list = def->content;
03154                 while (list != NULL) {
03155                     xmlRelaxNGCompile(ctxt, list);
03156                     list = list->next;
03157                 }
03158                 oldstate = ctxt->state;
03159                 list = def->content;
03160                 while (list != NULL) {
03161                     xmlRelaxNGCompile(ctxt, list);
03162                     list = list->next;
03163                 }
03164                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
03165                 ctxt->state =
03166                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
03167                 break;
03168             }
03169         case XML_RELAXNG_CHOICE:{
03170                 xmlAutomataStatePtr target = NULL;
03171                 xmlAutomataStatePtr oldstate = ctxt->state;
03172 
03173                 list = def->content;
03174                 while (list != NULL) {
03175                     ctxt->state = oldstate;
03176                     ret = xmlRelaxNGCompile(ctxt, list);
03177                     if (ret != 0)
03178                         break;
03179                     if (target == NULL)
03180                         target = ctxt->state;
03181                     else {
03182                         xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
03183                                               target);
03184                     }
03185                     list = list->next;
03186                 }
03187                 ctxt->state = target;
03188 
03189                 break;
03190             }
03191         case XML_RELAXNG_REF:
03192         case XML_RELAXNG_EXTERNALREF:
03193         case XML_RELAXNG_PARENTREF:
03194         case XML_RELAXNG_GROUP:
03195         case XML_RELAXNG_DEF:
03196             list = def->content;
03197             while (list != NULL) {
03198                 ret = xmlRelaxNGCompile(ctxt, list);
03199                 if (ret != 0)
03200                     break;
03201                 list = list->next;
03202             }
03203             break;
03204         case XML_RELAXNG_TEXT:{
03205                 xmlAutomataStatePtr oldstate;
03206 
03207                 ctxt->state =
03208                     xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
03209                 oldstate = ctxt->state;
03210                 xmlRelaxNGCompile(ctxt, def->content);
03211                 xmlAutomataNewTransition(ctxt->am, ctxt->state,
03212                                          ctxt->state, BAD_CAST "#text",
03213                                          NULL);
03214                 ctxt->state =
03215                     xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
03216                 break;
03217             }
03218         case XML_RELAXNG_EMPTY:
03219             ctxt->state =
03220                 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
03221             break;
03222         case XML_RELAXNG_EXCEPT:
03223         case XML_RELAXNG_ATTRIBUTE:
03224         case XML_RELAXNG_INTERLEAVE:
03225         case XML_RELAXNG_NOT_ALLOWED:
03226         case XML_RELAXNG_DATATYPE:
03227         case XML_RELAXNG_LIST:
03228         case XML_RELAXNG_PARAM:
03229         case XML_RELAXNG_VALUE:
03230             /* This should not happen and generate an internal error */
03231             fprintf(stderr, "RNG internal error trying to compile %s\n",
03232                     xmlRelaxNGDefName(def));
03233             break;
03234     }
03235     return (ret);
03236 }
03237 
03238 /**
03239  * xmlRelaxNGTryCompile:
03240  * ctxt:  the RelaxNG parser context
03241  * @define:  the definition tree to compile
03242  *
03243  * Try to compile the set of definitions, it works recursively,
03244  * possibly ignoring parts which cannot be compiled.
03245  *
03246  * Returns 0 if success and -1 in case of error
03247  */
03248 static int
03249 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
03250 {
03251     int ret = 0;
03252     xmlRelaxNGDefinePtr list;
03253 
03254     if ((ctxt == NULL) || (def == NULL))
03255         return (-1);
03256 
03257     if ((def->type == XML_RELAXNG_START) ||
03258         (def->type == XML_RELAXNG_ELEMENT)) {
03259         ret = xmlRelaxNGIsCompileable(def);
03260         if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
03261             ctxt->am = NULL;
03262             ret = xmlRelaxNGCompile(ctxt, def);
03263 #ifdef DEBUG_PROGRESSIVE
03264             if (ret == 0) {
03265                 if (def->type == XML_RELAXNG_START)
03266                     xmlGenericError(xmlGenericErrorContext,
03267                                     "compiled the start\n");
03268                 else
03269                     xmlGenericError(xmlGenericErrorContext,
03270                                     "compiled element %s\n", def->name);
03271             } else {
03272                 if (def->type == XML_RELAXNG_START)
03273                     xmlGenericError(xmlGenericErrorContext,
03274                                     "failed to compile the start\n");
03275                 else
03276                     xmlGenericError(xmlGenericErrorContext,
03277                                     "failed to compile element %s\n",
03278                                     def->name);
03279             }
03280 #endif
03281             return (ret);
03282         }
03283     }
03284     switch (def->type) {
03285         case XML_RELAXNG_NOOP:
03286             ret = xmlRelaxNGTryCompile(ctxt, def->content);
03287             break;
03288         case XML_RELAXNG_TEXT:
03289         case XML_RELAXNG_DATATYPE:
03290         case XML_RELAXNG_LIST:
03291         case XML_RELAXNG_PARAM:
03292         case XML_RELAXNG_VALUE:
03293         case XML_RELAXNG_EMPTY:
03294         case XML_RELAXNG_ELEMENT:
03295             ret = 0;
03296             break;
03297         case XML_RELAXNG_OPTIONAL:
03298         case XML_RELAXNG_ZEROORMORE:
03299         case XML_RELAXNG_ONEORMORE:
03300         case XML_RELAXNG_CHOICE:
03301         case XML_RELAXNG_GROUP:
03302         case XML_RELAXNG_DEF:
03303         case XML_RELAXNG_START:
03304         case XML_RELAXNG_REF:
03305         case XML_RELAXNG_EXTERNALREF:
03306         case XML_RELAXNG_PARENTREF:
03307             list = def->content;
03308             while (list != NULL) {
03309                 ret = xmlRelaxNGTryCompile(ctxt, list);
03310                 if (ret != 0)
03311                     break;
03312                 list = list->next;
03313             }
03314             break;
03315         case XML_RELAXNG_EXCEPT:
03316         case XML_RELAXNG_ATTRIBUTE:
03317         case XML_RELAXNG_INTERLEAVE:
03318         case XML_RELAXNG_NOT_ALLOWED:
03319             ret = 0;
03320             break;
03321     }
03322     return (ret);
03323 }
03324 
03325 /************************************************************************
03326  *                                  *
03327  *          Parsing functions               *
03328  *                                  *
03329  ************************************************************************/
03330 
03331 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
03332                                                     ctxt, xmlNodePtr node);
03333 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
03334                                                   ctxt, xmlNodePtr node);
03335 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
03336                                                    ctxt, xmlNodePtr nodes,
03337                                                    int group);
03338 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
03339                                                   ctxt, xmlNodePtr node);
03340 static xmlRelaxNGPtr xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt,
03341                                              xmlNodePtr node);
03342 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
03343                                          xmlNodePtr nodes);
03344 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
03345                                                     ctxt, xmlNodePtr node,
03346                                                     xmlRelaxNGDefinePtr
03347                                                     def);
03348 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
03349                                                    ctxt, xmlNodePtr nodes);
03350 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
03351                                   xmlRelaxNGDefinePtr define,
03352                                   xmlNodePtr elem);
03353 
03354 
03355 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
03356 
03357 /**
03358  * xmlRelaxNGIsNullable:
03359  * @define:  the definition to verify
03360  *
03361  * Check if a definition is nullable.
03362  *
03363  * Returns 1 if yes, 0 if no and -1 in case of error
03364  */
03365 static int
03366 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define)
03367 {
03368     int ret;
03369 
03370     if (define == NULL)
03371         return (-1);
03372 
03373     if (define->dflags & IS_NULLABLE)
03374         return (1);
03375     if (define->dflags & IS_NOT_NULLABLE)
03376         return (0);
03377     switch (define->type) {
03378         case XML_RELAXNG_EMPTY:
03379         case XML_RELAXNG_TEXT:
03380             ret = 1;
03381             break;
03382         case XML_RELAXNG_NOOP:
03383         case XML_RELAXNG_DEF:
03384         case XML_RELAXNG_REF:
03385         case XML_RELAXNG_EXTERNALREF:
03386         case XML_RELAXNG_PARENTREF:
03387         case XML_RELAXNG_ONEORMORE:
03388             ret = xmlRelaxNGIsNullable(define->content);
03389             break;
03390         case XML_RELAXNG_EXCEPT:
03391         case XML_RELAXNG_NOT_ALLOWED:
03392         case XML_RELAXNG_ELEMENT:
03393         case XML_RELAXNG_DATATYPE:
03394         case XML_RELAXNG_PARAM:
03395         case XML_RELAXNG_VALUE:
03396         case XML_RELAXNG_LIST:
03397         case XML_RELAXNG_ATTRIBUTE:
03398             ret = 0;
03399             break;
03400         case XML_RELAXNG_CHOICE:{
03401                 xmlRelaxNGDefinePtr list = define->content;
03402 
03403                 while (list != NULL) {
03404                     ret = xmlRelaxNGIsNullable(list);
03405                     if (ret != 0)
03406                         goto done;
03407                     list = list->next;
03408                 }
03409                 ret = 0;
03410                 break;
03411             }
03412         case XML_RELAXNG_START:
03413         case XML_RELAXNG_INTERLEAVE:
03414         case XML_RELAXNG_GROUP:{
03415                 xmlRelaxNGDefinePtr list = define->content;
03416 
03417                 while (list != NULL) {
03418                     ret = xmlRelaxNGIsNullable(list);
03419                     if (ret != 1)
03420                         goto done;
03421                     list = list->next;
03422                 }
03423                 return (1);
03424             }
03425         default:
03426             return (-1);
03427     }
03428   done:
03429     if (ret == 0)
03430         define->dflags |= IS_NOT_NULLABLE;
03431     if (ret == 1)
03432         define->dflags |= IS_NULLABLE;
03433     return (ret);
03434 }
03435 
03436 /**
03437  * xmlRelaxNGIsBlank:
03438  * @str:  a string
03439  *
03440  * Check if a string is ignorable c.f. 4.2. Whitespace
03441  *
03442  * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
03443  */
03444 static int
03445 xmlRelaxNGIsBlank(xmlChar * str)
03446 {
03447     if (str == NULL)
03448         return (1);
03449     while (*str != 0) {
03450         if (!(IS_BLANK_CH(*str)))
03451             return (0);
03452         str++;
03453     }
03454     return (1);
03455 }
03456 
03457 /**
03458  * xmlRelaxNGGetDataTypeLibrary:
03459  * @ctxt:  a Relax-NG parser context
03460  * @node:  the current data or value element
03461  *
03462  * Applies algorithm from 4.3. datatypeLibrary attribute
03463  *
03464  * Returns the datatypeLibary value or NULL if not found
03465  */
03466 static xmlChar *
03467 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
03468                              xmlNodePtr node)
03469 {
03470     xmlChar *ret, *escape;
03471 
03472     if (node == NULL)
03473         return(NULL);
03474 
03475     if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
03476         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
03477         if (ret != NULL) {
03478             if (ret[0] == 0) {
03479                 xmlFree(ret);
03480                 return (NULL);
03481             }
03482             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
03483             if (escape == NULL) {
03484                 return (ret);
03485             }
03486             xmlFree(ret);
03487             return (escape);
03488         }
03489     }
03490     node = node->parent;
03491     while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
03492         ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
03493         if (ret != NULL) {
03494             if (ret[0] == 0) {
03495                 xmlFree(ret);
03496                 return (NULL);
03497             }
03498             escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
03499             if (escape == NULL) {
03500                 return (ret);
03501             }
03502             xmlFree(ret);
03503             return (escape);
03504         }
03505         node = node->parent;
03506     }
03507     return (NULL);
03508 }
03509 
03510 /**
03511  * xmlRelaxNGParseValue:
03512  * @ctxt:  a Relax-NG parser context
03513  * @node:  the data node.
03514  *
03515  * parse the content of a RelaxNG value node.
03516  *
03517  * Returns the definition pointer or NULL in case of error
03518  */
03519 static xmlRelaxNGDefinePtr
03520 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
03521 {
03522     xmlRelaxNGDefinePtr def = NULL;
03523     xmlRelaxNGTypeLibraryPtr lib = NULL;
03524     xmlChar *type;
03525     xmlChar *library;
03526     int success = 0;
03527 
03528     def = xmlRelaxNGNewDefine(ctxt, node);
03529     if (def == NULL)
03530         return (NULL);
03531     def->type = XML_RELAXNG_VALUE;
03532 
03533     type = xmlGetProp(node, BAD_CAST "type");
03534     if (type != NULL) {
03535         xmlRelaxNGNormExtSpace(type);
03536         if (xmlValidateNCName(type, 0)) {
03537             xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
03538                        "value type '%s' is not an NCName\n", type, NULL);
03539         }
03540         library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
03541         if (library == NULL)
03542             library =
03543                 xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
03544 
03545         def->name = type;
03546         def->ns = library;
03547 
03548         lib = (xmlRelaxNGTypeLibraryPtr)
03549             xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
03550         if (lib == NULL) {
03551             xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
03552                        "Use of unregistered type library '%s'\n", library,
03553                        NULL);
03554             def->data = NULL;
03555         } else {
03556             def->data = lib;
03557             if (lib->have == NULL) {
03558                 xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
03559                            "Internal error with type library '%s': no 'have'\n",
03560                            library, NULL);
03561             } else {
03562                 success = lib->have(lib->data, def->name);
03563                 if (success != 1) {
03564                     xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
03565                                "Error type '%s' is not exported by type library '%s'\n",
03566                                def->name, library);
03567                 }
03568             }
03569         }
03570     }
03571     if (node->children == NULL) {
03572         def->value = xmlStrdup(BAD_CAST "");
03573     } else if (((node->children->type != XML_TEXT_NODE) &&
03574                 (node->children->type != XML_CDATA_SECTION_NODE)) ||
03575                (node->children->next != NULL)) {
03576         xmlRngPErr(ctxt, node, XML_RNGP_TEXT_EXPECTED,
03577                    "Expecting a single text value for <value>content\n",
03578                    NULL, NULL);
03579     } else if (def != NULL) {
03580         def->value = xmlNodeGetContent(node);
03581         if (def->value == NULL) {
03582             xmlRngPErr(ctxt, node, XML_RNGP_VALUE_NO_CONTENT,
03583                        "Element <value> has no content\n", NULL, NULL);
03584         } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
03585             void *val = NULL;
03586 
03587             success =
03588                 lib->check(lib->data, def->name, def->value, &val, node);
03589             if (success != 1) {
03590                 xmlRngPErr(ctxt, node, XML_RNGP_INVALID_VALUE,
03591                            "Value '%s' is not acceptable for type '%s'\n",
03592                            def->value, def->name);
03593             } else {
03594                 if (val != NULL)
03595                     def->attrs = val;
03596             }
03597         }
03598     }
03599     return (def);
03600 }
03601 
03602 /**
03603  * xmlRelaxNGParseData:
03604  * @ctxt:  a Relax-NG parser context
03605  * @node:  the data node.
03606  *
03607  * parse the content of a RelaxNG data node.
03608  *
03609  * Returns the definition pointer or NULL in case of error
03610  */
03611 static xmlRelaxNGDefinePtr
03612 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
03613 {
03614     xmlRelaxNGDefinePtr def = NULL, except;
03615     xmlRelaxNGDefinePtr param, lastparam = NULL;
03616     xmlRelaxNGTypeLibraryPtr lib;
03617     xmlChar *type;
03618     xmlChar *library;
03619     xmlNodePtr content;
03620     int tmp;
03621 
03622     type = xmlGetProp(node, BAD_CAST "type");
03623     if (type == NULL) {
03624         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_MISSING, "data has no type\n", NULL,
03625                    NULL);
03626         return (NULL);
03627     }
03628     xmlRelaxNGNormExtSpace(type);
03629     if (xmlValidateNCName(type, 0)) {
03630         xmlRngPErr(ctxt, node, XML_RNGP_TYPE_VALUE,
03631                    "data type '%s' is not an NCName\n", type, NULL);
03632     }
03633     library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
03634     if (library == NULL)
03635         library =
03636             xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
03637 
03638     def = xmlRelaxNGNewDefine(ctxt, node);
03639     if (def == NULL) {
03640         xmlFree(type);
03641         return (NULL);
03642     }
03643     def->type = XML_RELAXNG_DATATYPE;
03644     def->name = type;
03645     def->ns = library;
03646 
03647     lib = (xmlRelaxNGTypeLibraryPtr)
03648         xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
03649     if (lib == NULL) {
03650         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_TYPE_LIB,
03651                    "Use of unregistered type library '%s'\n", library,
03652                    NULL);
03653         def->data = NULL;
03654     } else {
03655         def->data = lib;
03656         if (lib->have == NULL) {
03657             xmlRngPErr(ctxt, node, XML_RNGP_ERROR_TYPE_LIB,
03658                        "Internal error with type library '%s': no 'have'\n",
03659                        library, NULL);
03660         } else {
03661             tmp = lib->have(lib->data, def->name);
03662             if (tmp != 1) {
03663                 xmlRngPErr(ctxt, node, XML_RNGP_TYPE_NOT_FOUND,
03664                            "Error type '%s' is not exported by type library '%s'\n",
03665                            def->name, library);
03666             } else
03667                 if ((xmlStrEqual
03668                      (library,
03669                       BAD_CAST
03670                       "http://www.w3.org/2001/XMLSchema-datatypes"))
03671                     && ((xmlStrEqual(def->name, BAD_CAST "IDREF"))
03672                         || (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
03673                 ctxt->idref = 1;
03674             }
03675         }
03676     }
03677     content = node->children;
03678 
03679     /*
03680      * Handle optional params
03681      */
03682     while (content != NULL) {
03683         if (!xmlStrEqual(content->name, BAD_CAST "param"))
03684             break;
03685         if (xmlStrEqual(library,
03686                         BAD_CAST "http://relaxng.org/ns/structure/1.0")) {
03687             xmlRngPErr(ctxt, node, XML_RNGP_PARAM_FORBIDDEN,
03688                        "Type library '%s' does not allow type parameters\n",
03689                        library, NULL);
03690             content = content->next;
03691             while ((content != NULL) &&
03692                    (xmlStrEqual(content->name, BAD_CAST "param")))
03693                 content = content->next;
03694         } else {
03695             param = xmlRelaxNGNewDefine(ctxt, node);
03696             if (param != NULL) {
03697                 param->type = XML_RELAXNG_PARAM;
03698                 param->name = xmlGetProp(content, BAD_CAST "name");
03699                 if (param->name == NULL) {
03700                     xmlRngPErr(ctxt, node, XML_RNGP_PARAM_NAME_MISSING,
03701                                "param has no name\n", NULL, NULL);
03702                 }
03703                 param->value = xmlNodeGetContent(content);
03704                 if (lastparam == NULL) {
03705                     def->attrs = lastparam = param;
03706                 } else {
03707                     lastparam->next = param;
03708                     lastparam = param;
03709                 }
03710                 if (lib != NULL) {
03711                 }
03712             }
03713             content = content->next;
03714         }
03715     }
03716     /*
03717      * Handle optional except
03718      */
03719     if ((content != NULL)
03720         && (xmlStrEqual(content->name, BAD_CAST "except"))) {
03721         xmlNodePtr child;
03722         xmlRelaxNGDefinePtr tmp2, last = NULL;
03723 
03724         except = xmlRelaxNGNewDefine(ctxt, node);
03725         if (except == NULL) {
03726             return (def);
03727         }
03728         except->type = XML_RELAXNG_EXCEPT;
03729         child = content->children;
03730     def->content = except;
03731         if (child == NULL) {
03732             xmlRngPErr(ctxt, content, XML_RNGP_EXCEPT_NO_CONTENT,
03733                        "except has no content\n", NULL, NULL);
03734         }
03735         while (child != NULL) {
03736             tmp2 = xmlRelaxNGParsePattern(ctxt, child);
03737             if (tmp2 != NULL) {
03738                 if (last == NULL) {
03739                     except->content = last = tmp2;
03740                 } else {
03741                     last->next = tmp2;
03742                     last = tmp2;
03743                 }
03744             }
03745             child = child->next;
03746         }
03747         content = content->next;
03748     }
03749     /*
03750      * Check there is no unhandled data
03751      */
03752     if (content != NULL) {
03753         xmlRngPErr(ctxt, content, XML_RNGP_DATA_CONTENT,
03754                    "Element data has unexpected content %s\n",
03755                    content->name, NULL);
03756     }
03757 
03758     return (def);
03759 }
03760 
03761 static const xmlChar *invalidName = BAD_CAST "\1";
03762 
03763 /**
03764  * xmlRelaxNGCompareNameClasses:
03765  * @defs1:  the first element/attribute defs
03766  * @defs2:  the second element/attribute defs
03767  * @name:  the restriction on the name
03768  * @ns:  the restriction on the namespace
03769  *
03770  * Compare the 2 lists of element definitions. The comparison is
03771  * that if both lists do not accept the same QNames, it returns 1
03772  * If the 2 lists can accept the same QName the comparison returns 0
03773  *
03774  * Returns 1 disttinct, 0 if equal
03775  */
03776 static int
03777 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
03778                              xmlRelaxNGDefinePtr def2)
03779 {
03780     int ret = 1;
03781     xmlNode node;
03782     xmlNs ns;
03783     xmlRelaxNGValidCtxt ctxt;
03784 
03785     memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
03786 
03787     ctxt.flags = FLAGS_IGNORABLE | FLAGS_NOERROR;
03788 
03789     if ((def1->type == XML_RELAXNG_ELEMENT) ||
03790         (def1->type == XML_RELAXNG_ATTRIBUTE)) {
03791         if (def2->type == XML_RELAXNG_TEXT)
03792             return (1);
03793         if (def1->name != NULL) {
03794             node.name = def1->name;
03795         } else {
03796             node.name = invalidName;
03797         }
03798         if (def1->ns != NULL) {
03799             if (def1->ns[0] == 0) {
03800                 node.ns = NULL;
03801             } else {
03802             node.ns = &ns;
03803                 ns.href = def1->ns;
03804             }
03805         } else {
03806             node.ns = NULL;
03807         }
03808         if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
03809             if (def1->nameClass != NULL) {
03810                 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
03811             } else {
03812                 ret = 0;
03813             }
03814         } else {
03815             ret = 1;
03816         }
03817     } else if (def1->type == XML_RELAXNG_TEXT) {
03818         if (def2->type == XML_RELAXNG_TEXT)
03819             return (0);
03820         return (1);
03821     } else if (def1->type == XML_RELAXNG_EXCEPT) {
03822         ret = xmlRelaxNGCompareNameClasses(def1->content, def2);
03823     if (ret == 0)
03824         ret = 1;
03825     else if (ret == 1)
03826         ret = 0;
03827     } else {
03828         TODO ret = 0;
03829     }
03830     if (ret == 0)
03831         return (ret);
03832     if ((def2->type == XML_RELAXNG_ELEMENT) ||
03833         (def2->type == XML_RELAXNG_ATTRIBUTE)) {
03834         if (def2->name != NULL) {
03835             node.name = def2->name;
03836         } else {
03837             node.name = invalidName;
03838         }
03839         node.ns = &ns;
03840         if (def2->ns != NULL) {
03841             if (def2->ns[0] == 0) {
03842                 node.ns = NULL;
03843             } else {
03844                 ns.href = def2->ns;
03845             }
03846         } else {
03847             ns.href = invalidName;
03848         }
03849         if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
03850             if (def2->nameClass != NULL) {
03851                 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
03852             } else {
03853                 ret = 0;
03854             }
03855         } else {
03856             ret = 1;
03857         }
03858     } else {
03859         TODO ret = 0;
03860     }
03861 
03862     return (ret);
03863 }
03864 
03865 /**
03866  * xmlRelaxNGCompareElemDefLists:
03867  * @ctxt:  a Relax-NG parser context
03868  * @defs1:  the first list of element/attribute defs
03869  * @defs2:  the second list of element/attribute defs
03870  *
03871  * Compare the 2 lists of element or attribute definitions. The comparison
03872  * is that if both lists do not accept the same QNames, it returns 1
03873  * If the 2 lists can accept the same QName the comparison returns 0
03874  *
03875  * Returns 1 disttinct, 0 if equal
03876  */
03877 static int
03878 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
03879                               ATTRIBUTE_UNUSED, xmlRelaxNGDefinePtr * def1,
03880                               xmlRelaxNGDefinePtr * def2)
03881 {
03882     xmlRelaxNGDefinePtr *basedef2 = def2;
03883 
03884     if ((def1 == NULL) || (def2 == NULL))
03885         return (1);
03886     if ((*def1 == NULL) || (*def2 == NULL))
03887         return (1);
03888     while (*def1 != NULL) {
03889         while ((*def2) != NULL) {
03890             if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
03891                 return (0);
03892             def2++;
03893         }
03894         def2 = basedef2;
03895         def1++;
03896     }
03897     return (1);
03898 }
03899 
03900 /**
03901  * xmlRelaxNGGenerateAttributes:
03902  * @ctxt:  a Relax-NG parser context
03903  * @def:  the definition definition
03904  *
03905  * Check if the definition can only generate attributes
03906  *
03907  * Returns 1 if yes, 0 if no and -1 in case of error.
03908  */
03909 static int
03910 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
03911                              xmlRelaxNGDefinePtr def)
03912 {
03913     xmlRelaxNGDefinePtr parent, cur, tmp;
03914 
03915     /*
03916      * Don't run that check in case of error. Infinite recursion
03917      * becomes possible.
03918      */
03919     if (ctxt->nbErrors != 0)
03920         return (-1);
03921 
03922     parent = NULL;
03923     cur = def;
03924     while (cur != NULL) {
03925         if ((cur->type == XML_RELAXNG_ELEMENT) ||
03926             (cur->type == XML_RELAXNG_TEXT) ||
03927             (cur->type == XML_RELAXNG_DATATYPE) ||
03928             (cur->type == XML_RELAXNG_PARAM) ||
03929             (cur->type == XML_RELAXNG_LIST) ||
03930             (cur->type == XML_RELAXNG_VALUE) ||
03931             (cur->type == XML_RELAXNG_EMPTY))
03932             return (0);
03933         if ((cur->type == XML_RELAXNG_CHOICE) ||
03934             (cur->type == XML_RELAXNG_INTERLEAVE) ||
03935             (cur->type == XML_RELAXNG_GROUP) ||
03936             (cur->type == XML_RELAXNG_ONEORMORE) ||
03937             (cur->type == XML_RELAXNG_ZEROORMORE) ||
03938             (cur->type == XML_RELAXNG_OPTIONAL) ||
03939             (cur->type == XML_RELAXNG_PARENTREF) ||
03940             (cur->type == XML_RELAXNG_EXTERNALREF) ||
03941             (cur->type == XML_RELAXNG_REF) ||
03942             (cur->type == XML_RELAXNG_DEF)) {
03943             if (cur->content != NULL) {
03944                 parent = cur;
03945                 cur = cur->content;
03946                 tmp = cur;
03947                 while (tmp != NULL) {
03948                     tmp->parent = parent;
03949                     tmp = tmp->next;
03950                 }
03951                 continue;
03952             }
03953         }
03954         if (cur == def)
03955             break;
03956         if (cur->next != NULL) {
03957             cur = cur->next;
03958             continue;
03959         }
03960         do {
03961             cur = cur->parent;
03962             if (cur == NULL)
03963                 break;
03964             if (cur == def)
03965                 return (1);
03966             if (cur->next != NULL) {
03967                 cur = cur->next;
03968                 break;
03969             }
03970         } while (cur != NULL);
03971     }
03972     return (1);
03973 }
03974 
03975 /**
03976  * xmlRelaxNGGetElements:
03977  * @ctxt:  a Relax-NG parser context
03978  * @def:  the definition definition
03979  * @eora:  gather elements (0) or attributes (1)
03980  *
03981  * Compute the list of top elements a definition can generate
03982  *
03983  * Returns a list of elements or NULL if none was found.
03984  */
03985 static xmlRelaxNGDefinePtr *
03986 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
03987                       xmlRelaxNGDefinePtr def, int eora)
03988 {
03989     xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
03990     int len = 0;
03991     int max = 0;
03992 
03993     /*
03994      * Don't run that check in case of error. Infinite recursion
03995      * becomes possible.
03996      */
03997     if (ctxt->nbErrors != 0)
03998         return (NULL);
03999 
04000     parent = NULL;
04001     cur = def;
04002     while (cur != NULL) {
04003         if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
04004                              (cur->type == XML_RELAXNG_TEXT))) ||
04005             ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
04006             if (ret == NULL) {
04007                 max = 10;
04008                 ret = (xmlRelaxNGDefinePtr *)
04009                     xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
04010                 if (ret == NULL) {
04011                     xmlRngPErrMemory(ctxt, "getting element list\n");
04012                     return (NULL);
04013                 }
04014             } else if (max <= len) {
04015             xmlRelaxNGDefinePtr *temp;
04016 
04017                 max *= 2;
04018                 temp = xmlRealloc(ret,
04019                                (max + 1) * sizeof(xmlRelaxNGDefinePtr));
04020                 if (temp == NULL) {
04021                     xmlRngPErrMemory(ctxt, "getting element list\n");
04022             xmlFree(ret);
04023                     return (NULL);
04024                 }
04025         ret = temp;
04026             }
04027             ret[len++] = cur;
04028             ret[len] = NULL;
04029         } else if ((cur->type == XML_RELAXNG_CHOICE) ||
04030                    (cur->type == XML_RELAXNG_INTERLEAVE) ||
04031                    (cur->type == XML_RELAXNG_GROUP) ||
04032                    (cur->type == XML_RELAXNG_ONEORMORE) ||
04033                    (cur->type == XML_RELAXNG_ZEROORMORE) ||
04034                    (cur->type == XML_RELAXNG_OPTIONAL) ||
04035                    (cur->type == XML_RELAXNG_PARENTREF) ||
04036                    (cur->type == XML_RELAXNG_REF) ||
04037                    (cur->type == XML_RELAXNG_DEF) ||
04038            (cur->type == XML_RELAXNG_EXTERNALREF)) {
04039             /*
04040              * Don't go within elements or attributes or string values.
04041              * Just gather the element top list
04042              */
04043             if (cur->content != NULL) {
04044                 parent = cur;
04045                 cur = cur->content;
04046                 tmp = cur;
04047                 while (tmp != NULL) {
04048                     tmp->parent = parent;
04049                     tmp = tmp->next;
04050                 }
04051                 continue;
04052             }
04053         }
04054         if (cur == def)
04055             break;
04056         if (cur->next != NULL) {
04057             cur = cur->next;
04058             continue;
04059         }
04060         do {
04061             cur = cur->parent;
04062             if (cur == NULL)
04063                 break;
04064             if (cur == def)
04065                 return (ret);
04066             if (cur->next != NULL) {
04067                 cur = cur->next;
04068                 break;
04069             }
04070         } while (cur != NULL);
04071     }
04072     return (ret);
04073 }
04074 
04075 /**
04076  * xmlRelaxNGCheckChoiceDeterminism:
04077  * @ctxt:  a Relax-NG parser context
04078  * @def:  the choice definition
04079  *
04080  * Also used to find indeterministic pattern in choice
04081  */
04082 static void
04083 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
04084                                  xmlRelaxNGDefinePtr def)
04085 {
04086     xmlRelaxNGDefinePtr **list;
04087     xmlRelaxNGDefinePtr cur;
04088     int nbchild = 0, i, j, ret;
04089     int is_nullable = 0;
04090     int is_indeterminist = 0;
04091     xmlHashTablePtr triage = NULL;
04092     int is_triable = 1;
04093 
04094     if ((def == NULL) || (def->type != XML_RELAXNG_CHOICE))
04095         return;
04096 
04097     if (def->dflags & IS_PROCESSED)
04098         return;
04099 
04100     /*
04101      * Don't run that check in case of error. Infinite recursion
04102      * becomes possible.
04103      */
04104     if (ctxt->nbErrors != 0)
04105         return;
04106 
04107     is_nullable = xmlRelaxNGIsNullable(def);
04108 
04109     cur = def->content;
04110     while (cur != NULL) {
04111         nbchild++;
04112         cur = cur->next;
04113     }
04114 
04115     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
04116                                               sizeof(xmlRelaxNGDefinePtr
04117                                                      *));
04118     if (list == NULL) {
04119         xmlRngPErrMemory(ctxt, "building choice\n");
04120         return;
04121     }
04122     i = 0;
04123     /*
04124      * a bit strong but safe
04125      */
04126     if (is_nullable == 0) {
04127         triage = xmlHashCreate(10);
04128     } else {
04129         is_triable = 0;
04130     }
04131     cur = def->content;
04132     while (cur != NULL) {
04133         list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
04134         if ((list[i] == NULL) || (list[i][0] == NULL)) {
04135             is_triable = 0;
04136         } else if (is_triable == 1) {
04137             xmlRelaxNGDefinePtr *tmp;
04138             int res;
04139 
04140             tmp = list[i];
04141             while ((*tmp != NULL) && (is_triable == 1)) {
04142                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
04143                     res = xmlHashAddEntry2(triage,
04144                                            BAD_CAST "#text", NULL,
04145                                            (void *) cur);
04146                     if (res != 0)
04147                         is_triable = -1;
04148                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
04149                            ((*tmp)->name != NULL)) {
04150                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
04151                         res = xmlHashAddEntry2(triage,
04152                                                (*tmp)->name, NULL,
04153                                                (void *) cur);
04154                     else
04155                         res = xmlHashAddEntry2(triage,
04156                                                (*tmp)->name, (*tmp)->ns,
04157                                                (void *) cur);
04158                     if (res != 0)
04159                         is_triable = -1;
04160                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
04161                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
04162                         res = xmlHashAddEntry2(triage,
04163                                                BAD_CAST "#any", NULL,
04164                                                (void *) cur);
04165                     else
04166                         res = xmlHashAddEntry2(triage,
04167                                                BAD_CAST "#any", (*tmp)->ns,
04168                                                (void *) cur);
04169                     if (res != 0)
04170                         is_triable = -1;
04171                 } else {
04172                     is_triable = -1;
04173                 }
04174                 tmp++;
04175             }
04176         }
04177         i++;
04178         cur = cur->next;
04179     }
04180 
04181     for (i = 0; i < nbchild; i++) {
04182         if (list[i] == NULL)
04183             continue;
04184         for (j = 0; j < i; j++) {
04185             if (list[j] == NULL)
04186                 continue;
04187             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
04188             if (ret == 0) {
04189                 is_indeterminist = 1;
04190             }
04191         }
04192     }
04193     for (i = 0; i < nbchild; i++) {
04194         if (list[i] != NULL)
04195             xmlFree(list[i]);
04196     }
04197 
04198     xmlFree(list);
04199     if (is_indeterminist) {
04200         def->dflags |= IS_INDETERMINIST;
04201     }
04202     if (is_triable == 1) {
04203         def->dflags |= IS_TRIABLE;
04204         def->data = triage;
04205     } else if (triage != NULL) {
04206         xmlHashFree(triage, NULL);
04207     }
04208     def->dflags |= IS_PROCESSED;
04209 }
04210 
04211 /**
04212  * xmlRelaxNGCheckGroupAttrs:
04213  * @ctxt:  a Relax-NG parser context
04214  * @def:  the group definition
04215  *
04216  * Detects violations of rule 7.3
04217  */
04218 static void
04219 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
04220                           xmlRelaxNGDefinePtr def)
04221 {
04222     xmlRelaxNGDefinePtr **list;
04223     xmlRelaxNGDefinePtr cur;
04224     int nbchild = 0, i, j, ret;
04225 
04226     if ((def == NULL) ||
04227         ((def->type != XML_RELAXNG_GROUP) &&
04228          (def->type != XML_RELAXNG_ELEMENT)))
04229         return;
04230 
04231     if (def->dflags & IS_PROCESSED)
04232         return;
04233 
04234     /*
04235      * Don't run that check in case of error. Infinite recursion
04236      * becomes possible.
04237      */
04238     if (ctxt->nbErrors != 0)
04239         return;
04240 
04241     cur = def->attrs;
04242     while (cur != NULL) {
04243         nbchild++;
04244         cur = cur->next;
04245     }
04246     cur = def->content;
04247     while (cur != NULL) {
04248         nbchild++;
04249         cur = cur->next;
04250     }
04251 
04252     list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
04253                                               sizeof(xmlRelaxNGDefinePtr
04254                                                      *));
04255     if (list == NULL) {
04256         xmlRngPErrMemory(ctxt, "building group\n");
04257         return;
04258     }
04259     i = 0;
04260     cur = def->attrs;
04261     while (cur != NULL) {
04262         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
04263         i++;
04264         cur = cur->next;
04265     }
04266     cur = def->content;
04267     while (cur != NULL) {
04268         list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
04269         i++;
04270         cur = cur->next;
04271     }
04272 
04273     for (i = 0; i < nbchild; i++) {
04274         if (list[i] == NULL)
04275             continue;
04276         for (j = 0; j < i; j++) {
04277             if (list[j] == NULL)
04278                 continue;
04279             ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
04280             if (ret == 0) {
04281                 xmlRngPErr(ctxt, def->node, XML_RNGP_GROUP_ATTR_CONFLICT,
04282                            "Attributes conflicts in group\n", NULL, NULL);
04283             }
04284         }
04285     }
04286     for (i = 0; i < nbchild; i++) {
04287         if (list[i] != NULL)
04288             xmlFree(list[i]);
04289     }
04290 
04291     xmlFree(list);
04292     def->dflags |= IS_PROCESSED;
04293 }
04294 
04295 /**
04296  * xmlRelaxNGComputeInterleaves:
04297  * @def:  the interleave definition
04298  * @ctxt:  a Relax-NG parser context
04299  * @name:  the definition name
04300  *
04301  * A lot of work for preprocessing interleave definitions
04302  * is potentially needed to get a decent execution speed at runtime
04303  *   - trying to get a total order on the element nodes generated
04304  *     by the interleaves, order the list of interleave definitions
04305  *     following that order.
04306  *   - if <text/> is used to handle mixed content, it is better to
04307  *     flag this in the define and simplify the runtime checking
04308  *     algorithm
04309  */
04310 static void
04311 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
04312                              xmlRelaxNGParserCtxtPtr ctxt,
04313                              xmlChar * name ATTRIBUTE_UNUSED)
04314 {
04315     xmlRelaxNGDefinePtr cur, *tmp;
04316 
04317     xmlRelaxNGPartitionPtr partitions = NULL;
04318     xmlRelaxNGInterleaveGroupPtr *groups = NULL;
04319     xmlRelaxNGInterleaveGroupPtr group;
04320     int i, j, ret, res;
04321     int nbgroups = 0;
04322     int nbchild = 0;
04323     int is_mixed = 0;
04324     int is_determinist = 1;
04325 
04326     /*
04327      * Don't run that check in case of error. Infinite recursion
04328      * becomes possible.
04329      */
04330     if (ctxt->nbErrors != 0)
04331         return;
04332 
04333 #ifdef DEBUG_INTERLEAVE
04334     xmlGenericError(xmlGenericErrorContext,
04335                     "xmlRelaxNGComputeInterleaves(%s)\n", name);
04336 #endif
04337     cur = def->content;
04338     while (cur != NULL) {
04339         nbchild++;
04340         cur = cur->next;
04341     }
04342 
04343 #ifdef DEBUG_INTERLEAVE
04344     xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild);
04345 #endif
04346     groups = (xmlRelaxNGInterleaveGroupPtr *)
04347         xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
04348     if (groups == NULL)
04349         goto error;
04350     cur = def->content;
04351     while (cur != NULL) {
04352         groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
04353             xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
04354         if (groups[nbgroups] == NULL)
04355             goto error;
04356         if (cur->type == XML_RELAXNG_TEXT)
04357             is_mixed++;
04358         groups[nbgroups]->rule = cur;
04359         groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
04360         groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
04361         nbgroups++;
04362         cur = cur->next;
04363     }
04364 #ifdef DEBUG_INTERLEAVE
04365     xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups);
04366 #endif
04367 
04368     /*
04369      * Let's check that all rules makes a partitions according to 7.4
04370      */
04371     partitions = (xmlRelaxNGPartitionPtr)
04372         xmlMalloc(sizeof(xmlRelaxNGPartition));
04373     if (partitions == NULL)
04374         goto error;
04375     memset(partitions, 0, sizeof(xmlRelaxNGPartition));
04376     partitions->nbgroups = nbgroups;
04377     partitions->triage = xmlHashCreate(nbgroups);
04378     for (i = 0; i < nbgroups; i++) {
04379         group = groups[i];
04380         for (j = i + 1; j < nbgroups; j++) {
04381             if (groups[j] == NULL)
04382                 continue;
04383 
04384             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
04385                                                 groups[j]->defs);
04386             if (ret == 0) {
04387                 xmlRngPErr(ctxt, def->node, XML_RNGP_ELEM_TEXT_CONFLICT,
04388                            "Element or text conflicts in interleave\n",
04389                            NULL, NULL);
04390             }
04391             ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
04392                                                 groups[j]->attrs);
04393             if (ret == 0) {
04394                 xmlRngPErr(ctxt, def->node, XML_RNGP_ATTR_CONFLICT,
04395                            "Attributes conflicts in interleave\n", NULL,
04396                            NULL);
04397             }
04398         }
04399         tmp = group->defs;
04400         if ((tmp != NULL) && (*tmp != NULL)) {
04401             while (*tmp != NULL) {
04402                 if ((*tmp)->type == XML_RELAXNG_TEXT) {
04403                     res = xmlHashAddEntry2(partitions->triage,
04404                                            BAD_CAST "#text", NULL,
04405                                            (void *) (long) (i + 1));
04406                     if (res != 0)
04407                         is_determinist = -1;
04408                 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
04409                            ((*tmp)->name != NULL)) {
04410                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
04411                         res = xmlHashAddEntry2(partitions->triage,
04412                                                (*tmp)->name, NULL,
04413                                                (void *) (long) (i + 1));
04414                     else
04415                         res = xmlHashAddEntry2(partitions->triage,
04416                                                (*tmp)->name, (*tmp)->ns,
04417                                                (void *) (long) (i + 1));
04418                     if (res != 0)
04419                         is_determinist = -1;
04420                 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
04421                     if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
04422                         res = xmlHashAddEntry2(partitions->triage,
04423                                                BAD_CAST "#any", NULL,
04424                                                (void *) (long) (i + 1));
04425                     else
04426                         res = xmlHashAddEntry2(partitions->triage,
04427                                                BAD_CAST "#any", (*tmp)->ns,
04428                                                (void *) (long) (i + 1));
04429                     if ((*tmp)->nameClass != NULL)
04430                         is_determinist = 2;
04431                     if (res != 0)
04432                         is_determinist = -1;
04433                 } else {
04434                     is_determinist = -1;
04435                 }
04436                 tmp++;
04437             }
04438         } else {
04439             is_determinist = 0;
04440         }
04441     }
04442     partitions->groups = groups;
04443 
04444     /*
04445      * and save the partition list back in the def
04446      */
04447     def->data = partitions;
04448     if (is_mixed != 0)
04449         def->dflags |= IS_MIXED;
04450     if (is_determinist == 1)
04451         partitions->flags = IS_DETERMINIST;
04452     if (is_determinist == 2)
04453         partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
04454     return;
04455 
04456   error:
04457     xmlRngPErrMemory(ctxt, "in interleave computation\n");
04458     if (groups != NULL) {
04459         for (i = 0; i < nbgroups; i++)
04460             if (groups[i] != NULL) {
04461                 if (groups[i]->defs != NULL)
04462                     xmlFree(groups[i]->defs);
04463                 xmlFree(groups[i]);
04464             }
04465         xmlFree(groups);
04466     }
04467     xmlRelaxNGFreePartition(partitions);
04468 }
04469 
04470 /**
04471  * xmlRelaxNGParseInterleave:
04472  * @ctxt:  a Relax-NG parser context
04473  * @node:  the data node.
04474  *
04475  * parse the content of a RelaxNG interleave node.
04476  *
04477  * Returns the definition pointer or NULL in case of error
04478  */
04479 static xmlRelaxNGDefinePtr
04480 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
04481 {
04482     xmlRelaxNGDefinePtr def = NULL;
04483     xmlRelaxNGDefinePtr last = NULL, cur;
04484     xmlNodePtr child;
04485 
04486     def = xmlRelaxNGNewDefine(ctxt, node);
04487     if (def == NULL) {
04488         return (NULL);
04489     }
04490     def->type = XML_RELAXNG_INTERLEAVE;
04491 
04492     if (ctxt->interleaves == NULL)
04493         ctxt->interleaves = xmlHashCreate(10);
04494     if (ctxt->interleaves == NULL) {
04495         xmlRngPErrMemory(ctxt, "create interleaves\n");
04496     } else {
04497         char name[32];
04498 
04499         snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
04500         if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
04501             xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_ADD,
04502                        "Failed to add %s to hash table\n",
04503                (const xmlChar *) name, NULL);
04504         }
04505     }
04506     child = node->children;
04507     if (child == NULL) {
04508         xmlRngPErr(ctxt, node, XML_RNGP_INTERLEAVE_NO_CONTENT,
04509                    "Element interleave is empty\n", NULL, NULL);
04510     }
04511     while (child != NULL) {
04512         if (IS_RELAXNG(child, "element")) {
04513             cur = xmlRelaxNGParseElement(ctxt, child);
04514         } else {
04515             cur = xmlRelaxNGParsePattern(ctxt, child);
04516         }
04517         if (cur != NULL) {
04518             cur->parent = def;
04519             if (last == NULL) {
04520                 def->content = last = cur;
04521             } else {
04522                 last->next = cur;
04523                 last = cur;
04524             }
04525         }
04526         child = child->next;
04527     }
04528 
04529     return (def);
04530 }
04531 
04532 /**
04533  * xmlRelaxNGParseInclude:
04534  * @ctxt:  a Relax-NG parser context
04535  * @node:  the include node
04536  *
04537  * Integrate the content of an include node in the current grammar
04538  *
04539  * Returns 0 in case of success or -1 in case of error
04540  */
04541 static int
04542 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
04543 {
04544     xmlRelaxNGIncludePtr incl;
04545     xmlNodePtr root;
04546     int ret = 0, tmp;
04547 
04548     incl = node->psvi;
04549     if (incl == NULL) {
04550         xmlRngPErr(ctxt, node, XML_RNGP_INCLUDE_EMPTY,
04551                    "Include node has no data\n", NULL, NULL);
04552         return (-1);
04553     }
04554     root = xmlDocGetRootElement(incl->doc);
04555     if (root == NULL) {
04556         xmlRngPErr(ctxt, node, XML_RNGP_EMPTY, "Include document is empty\n",
04557                    NULL, NULL);
04558         return (-1);
04559     }
04560     if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
04561         xmlRngPErr(ctxt, node, XML_RNGP_GRAMMAR_MISSING,
04562                    "Include document root is not a grammar\n", NULL, NULL);
04563         return (-1);
04564     }
04565 
04566     /*
04567      * Merge the definition from both the include and the internal list
04568      */
04569     if (root->children != NULL) {
04570         tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
04571         if (tmp != 0)
04572             ret = -1;
04573     }
04574     if (node->children != NULL) {
04575         tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
04576         if (tmp != 0)
04577             ret = -1;
04578     }
04579     return (ret);
04580 }
04581 
04582 /**
04583  * xmlRelaxNGParseDefine:
04584  * @ctxt:  a Relax-NG parser context
04585  * @node:  the define node
04586  *
04587  * parse the content of a RelaxNG define element node.
04588  *
04589  * Returns 0 in case of success or -1 in case of error
04590  */
04591 static int
04592 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
04593 {
04594     xmlChar *name;
04595     int ret = 0, tmp;
04596     xmlRelaxNGDefinePtr def;
04597     const xmlChar *olddefine;
04598 
04599     name = xmlGetProp(node, BAD_CAST "name");
04600     if (name == NULL) {
04601         xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_NAME_MISSING,
04602                    "define has no name\n", NULL, NULL);
04603     } else {
04604         xmlRelaxNGNormExtSpace(name);
04605         if (xmlValidateNCName(name, 0)) {
04606             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_DEFINE_NAME,
04607                        "define name '%s' is not an NCName\n", name, NULL);
04608         }
04609         def = xmlRelaxNGNewDefine(ctxt, node);
04610         if (def == NULL) {
04611             xmlFree(name);
04612             return (-1);
04613         }
04614         def->type = XML_RELAXNG_DEF;
04615         def->name = name;
04616         if (node->children == NULL) {
04617             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_EMPTY,
04618                        "define has no children\n", NULL, NULL);
04619         } else {
04620             olddefine = ctxt->define;
04621             ctxt->define = name;
04622             def->content =
04623                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
04624             ctxt->define = olddefine;
04625         }
04626         if (ctxt->grammar->defs == NULL)
04627             ctxt->grammar->defs = xmlHashCreate(10);
04628         if (ctxt->grammar->defs == NULL) {
04629             xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
04630                        "Could not create definition hash\n", NULL, NULL);
04631             ret = -1;
04632         } else {
04633             tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
04634             if (tmp < 0) {
04635                 xmlRelaxNGDefinePtr prev;
04636 
04637                 prev = xmlHashLookup(ctxt->grammar->defs, name);
04638                 if (prev == NULL) {
04639                     xmlRngPErr(ctxt, node, XML_RNGP_DEFINE_CREATE_FAILED,
04640                                "Internal error on define aggregation of %s\n",
04641                                name, NULL);
04642                     ret = -1;
04643                 } else {
04644                     while (prev->nextHash != NULL)
04645                         prev = prev->nextHash;
04646                     prev->nextHash = def;
04647                 }
04648             }
04649         }
04650     }
04651     return (ret);
04652 }
04653 
04654 /**
04655  * xmlRelaxNGParseImportRef:
04656  * @payload: the parser context
04657  * @data: the current grammar
04658  * @name: the reference name
04659  *
04660  * Import import one references into the current grammar
04661  */
04662 static void
04663 xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) {
04664     xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
04665     xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
04666     int tmp;
04667 
04668     def->dflags |= IS_EXTERNAL_REF;
04669 
04670     tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
04671     if (tmp < 0) {
04672         xmlRelaxNGDefinePtr prev;
04673 
04674         prev = (xmlRelaxNGDefinePtr)
04675             xmlHashLookup(ctxt->grammar->refs, def->name);
04676         if (prev == NULL) {
04677             if (def->name != NULL) {
04678                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
04679                            "Error refs definitions '%s'\n",
04680                            def->name, NULL);
04681             } else {
04682                 xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
04683                            "Error refs definitions\n",
04684                            NULL, NULL);
04685             }
04686         } else {
04687             def->nextHash = prev->nextHash;
04688             prev->nextHash = def;
04689         }
04690     }
04691 }
04692 
04693 /**
04694  * xmlRelaxNGParseImportRefs:
04695  * @ctxt: the parser context
04696  * @grammar: the sub grammar
04697  *
04698  * Import references from the subgrammar into the current grammar
04699  *
04700  * Returns 0 in case of success, -1 in case of failure
04701  */
04702 static int
04703 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
04704                           xmlRelaxNGGrammarPtr grammar) {
04705     if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
04706         return(-1);
04707     if (grammar->refs == NULL)
04708         return(0);
04709     if (ctxt->grammar->refs == NULL)
04710         ctxt->grammar->refs = xmlHashCreate(10);
04711     if (ctxt->grammar->refs == NULL) {
04712         xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
04713                    "Could not create references hash\n", NULL, NULL);
04714         return(-1);
04715     }
04716     xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
04717     return(0);
04718 }
04719 
04720 /**
04721  * xmlRelaxNGProcessExternalRef:
04722  * @ctxt: the parser context
04723  * @node:  the externlRef node
04724  *
04725  * Process and compile an externlRef node
04726  *
04727  * Returns the xmlRelaxNGDefinePtr or NULL in case of error
04728  */
04729 static xmlRelaxNGDefinePtr
04730 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
04731 {
04732     xmlRelaxNGDocumentPtr docu;
04733     xmlNodePtr root, tmp;
04734     xmlChar *ns;
04735     int newNs = 0, oldflags;
04736     xmlRelaxNGDefinePtr def;
04737 
04738     docu = node->psvi;
04739     if (docu != NULL) {
04740         def = xmlRelaxNGNewDefine(ctxt, node);
04741         if (def == NULL)
04742             return (NULL);
04743         def->type = XML_RELAXNG_EXTERNALREF;
04744 
04745         if (docu->content == NULL) {
04746             /*
04747              * Then do the parsing for good
04748              */
04749             root = xmlDocGetRootElement(docu->doc);
04750             if (root == NULL) {
04751                 xmlRngPErr(ctxt, node, XML_RNGP_EXTERNALREF_EMTPY,
04752                            "xmlRelaxNGParse: %s is empty\n", ctxt->URL,
04753                            NULL);
04754                 return (NULL);
04755             }
04756             /*
04757              * ns transmission rules
04758              */
04759             ns = xmlGetProp(root, BAD_CAST "ns");
04760             if (ns == NULL) {
04761                 tmp = node;
04762                 while ((tmp != NULL) && (tmp->type == XML_ELEMENT_NODE)) {
04763                     ns = xmlGetProp(tmp, BAD_CAST "ns");
04764                     if (ns != NULL) {
04765                         break;
04766                     }
04767                     tmp = tmp->parent;
04768                 }
04769                 if (ns != NULL) {
04770                     xmlSetProp(root, BAD_CAST "ns", ns);
04771                     newNs = 1;
04772                     xmlFree(ns);
04773                 }
04774             } else {
04775                 xmlFree(ns);
04776             }
04777 
04778             /*
04779              * Parsing to get a precompiled schemas.
04780              */
04781             oldflags = ctxt->flags;
04782             ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
04783             docu->schema = xmlRelaxNGParseDocument(ctxt, root);
04784             ctxt->flags = oldflags;
04785             if ((docu->schema != NULL) &&
04786                 (docu->schema->topgrammar != NULL)) {
04787                 docu->content = docu->schema->topgrammar->start;
04788                 if (docu->schema->topgrammar->refs)
04789                     xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
04790             }
04791 
04792             /*
04793              * the externalRef may be reused in a different ns context
04794              */
04795             if (newNs == 1) {
04796                 xmlUnsetProp(root, BAD_CAST "ns");
04797             }
04798         }
04799         def->content = docu->content;
04800     } else {
04801         def = NULL;
04802     }
04803     return (def);
04804 }
04805 
04806 /**
04807  * xmlRelaxNGParsePattern:
04808  * @ctxt:  a Relax-NG parser context
04809  * @node:  the pattern node.
04810  *
04811  * parse the content of a RelaxNG pattern node.
04812  *
04813  * Returns the definition pointer or NULL in case of error or if no
04814  *     pattern is generated.
04815  */
04816 static xmlRelaxNGDefinePtr
04817 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
04818 {
04819     xmlRelaxNGDefinePtr def = NULL;
04820 
04821     if (node == NULL) {
04822         return (NULL);
04823     }
04824     if (IS_RELAXNG(node, "element")) {
04825         def = xmlRelaxNGParseElement(ctxt, node);
04826     } else if (IS_RELAXNG(node, "attribute")) {
04827         def = xmlRelaxNGParseAttribute(ctxt, node);
04828     } else if (IS_RELAXNG(node, "empty")) {
04829         def = xmlRelaxNGNewDefine(ctxt, node);
04830         if (def == NULL)
04831             return (NULL);
04832         def->type = XML_RELAXNG_EMPTY;
04833         if (node->children != NULL) {
04834             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_NOT_EMPTY,
04835                        "empty: had a child node\n", NULL, NULL);
04836         }
04837     } else if (IS_RELAXNG(node, "text")) {
04838         def = xmlRelaxNGNewDefine(ctxt, node);
04839         if (def == NULL)
04840             return (NULL);
04841         def->type = XML_RELAXNG_TEXT;
04842         if (node->children != NULL) {
04843             xmlRngPErr(ctxt, node, XML_RNGP_TEXT_HAS_CHILD,
04844                        "text: had a child node\n", NULL, NULL);
04845         }
04846     } else if (IS_RELAXNG(node, "zeroOrMore")) {
04847         def = xmlRelaxNGNewDefine(ctxt, node);
04848         if (def == NULL)
04849             return (NULL);
04850         def->type = XML_RELAXNG_ZEROORMORE;
04851         if (node->children == NULL) {
04852             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
04853                        "Element %s is empty\n", node->name, NULL);
04854         } else {
04855             def->content =
04856                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
04857         }
04858     } else if (IS_RELAXNG(node, "oneOrMore")) {
04859         def = xmlRelaxNGNewDefine(ctxt, node);
04860         if (def == NULL)
04861             return (NULL);
04862         def->type = XML_RELAXNG_ONEORMORE;
04863         if (node->children == NULL) {
04864             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
04865                        "Element %s is empty\n", node->name, NULL);
04866         } else {
04867             def->content =
04868                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
04869         }
04870     } else if (IS_RELAXNG(node, "optional")) {
04871         def = xmlRelaxNGNewDefine(ctxt, node);
04872         if (def == NULL)
04873             return (NULL);
04874         def->type = XML_RELAXNG_OPTIONAL;
04875         if (node->children == NULL) {
04876             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
04877                        "Element %s is empty\n", node->name, NULL);
04878         } else {
04879             def->content =
04880                 xmlRelaxNGParsePatterns(ctxt, node->children, 1);
04881         }
04882     } else if (IS_RELAXNG(node, "choice")) {
04883         def = xmlRelaxNGNewDefine(ctxt, node);
04884         if (def == NULL)
04885             return (NULL);
04886         def->type = XML_RELAXNG_CHOICE;
04887         if (node->children == NULL) {
04888             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
04889                        "Element %s is empty\n", node->name, NULL);
04890         } else {
04891             def->content =
04892                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
04893         }
04894     } else if (IS_RELAXNG(node, "group")) {
04895         def = xmlRelaxNGNewDefine(ctxt, node);
04896         if (def == NULL)
04897             return (NULL);
04898         def->type = XML_RELAXNG_GROUP;
04899         if (node->children == NULL) {
04900             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
04901                        "Element %s is empty\n", node->name, NULL);
04902         } else {
04903             def->content =
04904                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
04905         }
04906     } else if (IS_RELAXNG(node, "ref")) {
04907         def = xmlRelaxNGNewDefine(ctxt, node);
04908         if (def == NULL)
04909             return (NULL);
04910         def->type = XML_RELAXNG_REF;
04911         def->name = xmlGetProp(node, BAD_CAST "name");
04912         if (def->name == NULL) {
04913             xmlRngPErr(ctxt, node, XML_RNGP_REF_NO_NAME, "ref has no name\n",
04914                        NULL, NULL);
04915         } else {
04916             xmlRelaxNGNormExtSpace(def->name);
04917             if (xmlValidateNCName(def->name, 0)) {
04918                 xmlRngPErr(ctxt, node, XML_RNGP_REF_NAME_INVALID,
04919                            "ref name '%s' is not an NCName\n", def->name,
04920                            NULL);
04921             }
04922         }
04923         if (node->children != NULL) {
04924             xmlRngPErr(ctxt, node, XML_RNGP_REF_NOT_EMPTY, "ref is not empty\n",
04925                        NULL, NULL);
04926         }
04927         if (ctxt->grammar->refs == NULL)
04928             ctxt->grammar->refs = xmlHashCreate(10);
04929         if (ctxt->grammar->refs == NULL) {
04930             xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
04931                        "Could not create references hash\n", NULL, NULL);
04932             def = NULL;
04933         } else {
04934             int tmp;
04935 
04936             tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
04937             if (tmp < 0) {
04938                 xmlRelaxNGDefinePtr prev;
04939 
04940                 prev = (xmlRelaxNGDefinePtr)
04941                     xmlHashLookup(ctxt->grammar->refs, def->name);
04942                 if (prev == NULL) {
04943                     if (def->name != NULL) {
04944                 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
04945                    "Error refs definitions '%s'\n",
04946                    def->name, NULL);
04947                     } else {
04948                 xmlRngPErr(ctxt, node, XML_RNGP_REF_CREATE_FAILED,
04949                    "Error refs definitions\n",
04950                    NULL, NULL);
04951                     }
04952                     def = NULL;
04953                 } else {
04954                     def->nextHash = prev->nextHash;
04955                     prev->nextHash = def;
04956                 }
04957             }
04958         }
04959     } else if (IS_RELAXNG(node, "data")) {
04960         def = xmlRelaxNGParseData(ctxt, node);
04961     } else if (IS_RELAXNG(node, "value")) {
04962         def = xmlRelaxNGParseValue(ctxt, node);
04963     } else if (IS_RELAXNG(node, "list")) {
04964         def = xmlRelaxNGNewDefine(ctxt, node);
04965         if (def == NULL)
04966             return (NULL);
04967         def->type = XML_RELAXNG_LIST;
04968         if (node->children == NULL) {
04969             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT,
04970                        "Element %s is empty\n", node->name, NULL);
04971         } else {
04972             def->content =
04973                 xmlRelaxNGParsePatterns(ctxt, node->children, 0);
04974         }
04975     } else if (IS_RELAXNG(node, "interleave")) {
04976         def = xmlRelaxNGParseInterleave(ctxt, node);
04977     } else if (IS_RELAXNG(node, "externalRef")) {
04978         def = xmlRelaxNGProcessExternalRef(ctxt, node);
04979     } else if (IS_RELAXNG(node, "notAllowed")) {
04980         def = xmlRelaxNGNewDefine(ctxt, node);
04981         if (def == NULL)
04982             return (NULL);
04983         def->type = XML_RELAXNG_NOT_ALLOWED;
04984         if (node->children != NULL) {
04985             xmlRngPErr(ctxt, node, XML_RNGP_NOTALLOWED_NOT_EMPTY,
04986                        "xmlRelaxNGParse: notAllowed element is not empty\n",
04987                        NULL, NULL);
04988         }
04989     } else if (IS_RELAXNG(node, "grammar")) {
04990         xmlRelaxNGGrammarPtr grammar, old;
04991         xmlRelaxNGGrammarPtr oldparent;
04992 
04993 #ifdef DEBUG_GRAMMAR
04994         xmlGenericError(xmlGenericErrorContext,
04995                         "Found <grammar> pattern\n");
04996 #endif
04997 
04998         oldparent = ctxt->parentgrammar;
04999         old = ctxt->grammar;
05000         ctxt->parentgrammar = old;
05001         grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
05002         if (old != NULL) {
05003             ctxt->grammar = old;
05004             ctxt->parentgrammar = oldparent;
05005 #if 0
05006             if (grammar != NULL) {
05007                 grammar->next = old->next;
05008                 old->next = grammar;
05009             }
05010 #endif
05011         }
05012         if (grammar != NULL)
05013             def = grammar->start;
05014         else
05015             def = NULL;
05016     } else if (IS_RELAXNG(node, "parentRef")) {
05017         if (ctxt->parentgrammar == NULL) {
05018             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_PARENT,
05019                        "Use of parentRef without a parent grammar\n", NULL,
05020                        NULL);
05021             return (NULL);
05022         }
05023         def = xmlRelaxNGNewDefine(ctxt, node);
05024         if (def == NULL)
05025             return (NULL);
05026         def->type = XML_RELAXNG_PARENTREF;
05027         def->name = xmlGetProp(node, BAD_CAST "name");
05028         if (def->name == NULL) {
05029             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NO_NAME,
05030                        "parentRef has no name\n", NULL, NULL);
05031         } else {
05032             xmlRelaxNGNormExtSpace(def->name);
05033             if (xmlValidateNCName(def->name, 0)) {
05034                 xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NAME_INVALID,
05035                            "parentRef name '%s' is not an NCName\n",
05036                            def->name, NULL);
05037             }
05038         }
05039         if (node->children != NULL) {
05040             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_NOT_EMPTY,
05041                        "parentRef is not empty\n", NULL, NULL);
05042         }
05043         if (ctxt->parentgrammar->refs == NULL)
05044             ctxt->parentgrammar->refs = xmlHashCreate(10);
05045         if (ctxt->parentgrammar->refs == NULL) {
05046             xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
05047                        "Could not create references hash\n", NULL, NULL);
05048             def = NULL;
05049         } else if (def->name != NULL) {
05050             int tmp;
05051 
05052             tmp =
05053                 xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
05054             if (tmp < 0) {
05055                 xmlRelaxNGDefinePtr prev;
05056 
05057                 prev = (xmlRelaxNGDefinePtr)
05058                     xmlHashLookup(ctxt->parentgrammar->refs, def->name);
05059                 if (prev == NULL) {
05060                     xmlRngPErr(ctxt, node, XML_RNGP_PARENTREF_CREATE_FAILED,
05061                                "Internal error parentRef definitions '%s'\n",
05062                                def->name, NULL);
05063                     def = NULL;
05064                 } else {
05065                     def->nextHash = prev->nextHash;
05066                     prev->nextHash = def;
05067                 }
05068             }
05069         }
05070     } else if (IS_RELAXNG(node, "mixed")) {
05071         if (node->children == NULL) {
05072             xmlRngPErr(ctxt, node, XML_RNGP_EMPTY_CONSTRUCT, "Mixed is empty\n",
05073                        NULL, NULL);
05074             def = NULL;
05075         } else {
05076             def = xmlRelaxNGParseInterleave(ctxt, node);
05077             if (def != NULL) {
05078                 xmlRelaxNGDefinePtr tmp;
05079 
05080                 if ((def->content != NULL) && (def->content->next != NULL)) {
05081                     tmp = xmlRelaxNGNewDefine(ctxt, node);
05082                     if (tmp != NULL) {
05083                         tmp->type = XML_RELAXNG_GROUP;
05084                         tmp->content = def->content;
05085                         def->content = tmp;
05086                     }
05087                 }
05088 
05089                 tmp = xmlRelaxNGNewDefine(ctxt, node);
05090                 if (tmp == NULL)
05091                     return (def);
05092                 tmp->type = XML_RELAXNG_TEXT;
05093                 tmp->next = def->content;
05094                 def->content = tmp;
05095             }
05096         }
05097     } else {
05098         xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_CONSTRUCT,
05099                    "Unexpected node %s is not a pattern\n", node->name,
05100                    NULL);
05101         def = NULL;
05102     }
05103     return (def);
05104 }
05105 
05106 /**
05107  * xmlRelaxNGParseAttribute:
05108  * @ctxt:  a Relax-NG parser context
05109  * @node:  the element node
05110  *
05111  * parse the content of a RelaxNG attribute node.
05112  *
05113  * Returns the definition pointer or NULL in case of error.
05114  */
05115 static xmlRelaxNGDefinePtr
05116 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
05117 {
05118     xmlRelaxNGDefinePtr ret, cur;
05119     xmlNodePtr child;
05120     int old_flags;
05121 
05122     ret = xmlRelaxNGNewDefine(ctxt, node);
05123     if (ret == NULL)
05124         return (NULL);
05125     ret->type = XML_RELAXNG_ATTRIBUTE;
05126     ret->parent = ctxt->def;
05127     child = node->children;
05128     if (child == NULL) {
05129         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_EMPTY,
05130                    "xmlRelaxNGParseattribute: attribute has no children\n",
05131                    NULL, NULL);
05132         return (ret);
05133     }
05134     old_flags = ctxt->flags;
05135     ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
05136     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
05137     if (cur != NULL)
05138         child = child->next;
05139 
05140     if (child != NULL) {
05141         cur = xmlRelaxNGParsePattern(ctxt, child);
05142         if (cur != NULL) {
05143             switch (cur->type) {
05144                 case XML_RELAXNG_EMPTY:
05145                 case XML_RELAXNG_NOT_ALLOWED:
05146                 case XML_RELAXNG_TEXT:
05147                 case XML_RELAXNG_ELEMENT:
05148                 case XML_RELAXNG_DATATYPE:
05149                 case XML_RELAXNG_VALUE:
05150                 case XML_RELAXNG_LIST:
05151                 case XML_RELAXNG_REF:
05152                 case XML_RELAXNG_PARENTREF:
05153                 case XML_RELAXNG_EXTERNALREF:
05154                 case XML_RELAXNG_DEF:
05155                 case XML_RELAXNG_ONEORMORE:
05156                 case XML_RELAXNG_ZEROORMORE:
05157                 case XML_RELAXNG_OPTIONAL:
05158                 case XML_RELAXNG_CHOICE:
05159                 case XML_RELAXNG_GROUP:
05160                 case XML_RELAXNG_INTERLEAVE:
05161                 case XML_RELAXNG_ATTRIBUTE:
05162                     ret->content = cur;
05163                     cur->parent = ret;
05164                     break;
05165                 case XML_RELAXNG_START:
05166                 case XML_RELAXNG_PARAM:
05167                 case XML_RELAXNG_EXCEPT:
05168                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CONTENT,
05169                                "attribute has invalid content\n", NULL,
05170                                NULL);
05171                     break;
05172                 case XML_RELAXNG_NOOP:
05173                     xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_NOOP,
05174                                "RNG Internal error, noop found in attribute\n",
05175                                NULL, NULL);
05176                     break;
05177             }
05178         }
05179         child = child->next;
05180     }
05181     if (child != NULL) {
05182         xmlRngPErr(ctxt, node, XML_RNGP_ATTRIBUTE_CHILDREN,
05183                    "attribute has multiple children\n", NULL, NULL);
05184     }
05185     ctxt->flags = old_flags;
05186     return (ret);
05187 }
05188 
05189 /**
05190  * xmlRelaxNGParseExceptNameClass:
05191  * @ctxt:  a Relax-NG parser context
05192  * @node:  the except node
05193  * @attr:  1 if within an attribute, 0 if within an element
05194  *
05195  * parse the content of a RelaxNG nameClass node.
05196  *
05197  * Returns the definition pointer or NULL in case of error.
05198  */
05199 static xmlRelaxNGDefinePtr
05200 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
05201                                xmlNodePtr node, int attr)
05202 {
05203     xmlRelaxNGDefinePtr ret, cur, last = NULL;
05204     xmlNodePtr child;
05205 
05206     if (!IS_RELAXNG(node, "except")) {
05207         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MISSING,
05208                    "Expecting an except node\n", NULL, NULL);
05209         return (NULL);
05210     }
05211     if (node->next != NULL) {
05212         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_MULTIPLE,
05213                    "exceptNameClass allows only a single except node\n",
05214                    NULL, NULL);
05215     }
05216     if (node->children == NULL) {
05217         xmlRngPErr(ctxt, node, XML_RNGP_EXCEPT_EMPTY, "except has no content\n",
05218                    NULL, NULL);
05219         return (NULL);
05220     }
05221 
05222     ret = xmlRelaxNGNewDefine(ctxt, node);
05223     if (ret == NULL)
05224         return (NULL);
05225     ret->type = XML_RELAXNG_EXCEPT;
05226     child = node->children;
05227     while (child != NULL) {
05228         cur = xmlRelaxNGNewDefine(ctxt, child);
05229         if (cur == NULL)
05230             break;
05231         if (attr)
05232             cur->type = XML_RELAXNG_ATTRIBUTE;
05233         else
05234             cur->type = XML_RELAXNG_ELEMENT;
05235 
05236         if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
05237             if (last == NULL) {
05238                 ret->content = cur;
05239             } else {
05240                 last->next = cur;
05241             }
05242             last = cur;
05243         }
05244         child = child->next;
05245     }
05246 
05247     return (ret);
05248 }
05249 
05250 /**
05251  * xmlRelaxNGParseNameClass:
05252  * @ctxt:  a Relax-NG parser context
05253  * @node:  the nameClass node
05254  * @def:  the current definition
05255  *
05256  * parse the content of a RelaxNG nameClass node.
05257  *
05258  * Returns the definition pointer or NULL in case of error.
05259  */
05260 static xmlRelaxNGDefinePtr
05261 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
05262                          xmlRelaxNGDefinePtr def)
05263 {
05264     xmlRelaxNGDefinePtr ret, tmp;
05265     xmlChar *val;
05266 
05267     ret = def;
05268     if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
05269         (IS_RELAXNG(node, "nsName"))) {
05270         if ((def->type != XML_RELAXNG_ELEMENT) &&
05271             (def->type != XML_RELAXNG_ATTRIBUTE)) {
05272             ret = xmlRelaxNGNewDefine(ctxt, node);
05273             if (ret == NULL)
05274                 return (NULL);
05275             ret->parent = def;
05276             if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
05277                 ret->type = XML_RELAXNG_ATTRIBUTE;
05278             else
05279                 ret->type = XML_RELAXNG_ELEMENT;
05280         }
05281     }
05282     if (IS_RELAXNG(node, "name")) {
05283         val = xmlNodeGetContent(node);
05284         xmlRelaxNGNormExtSpace(val);
05285         if (xmlValidateNCName(val, 0)) {
05286         if (node->parent != NULL)
05287         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
05288                "Element %s name '%s' is not an NCName\n",
05289                node->parent->name, val);
05290         else
05291         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NAME,
05292                "name '%s' is not an NCName\n",
05293                val, NULL);
05294         }
05295         ret->name = val;
05296         val = xmlGetProp(node, BAD_CAST "ns");
05297         ret->ns = val;
05298         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
05299             (val != NULL) &&
05300             (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
05301         xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
05302                         "Attribute with namespace '%s' is not allowed\n",
05303                         val, NULL);
05304         }
05305         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
05306             (val != NULL) &&
05307             (val[0] == 0) && (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
05308         xmlRngPErr(ctxt, node, XML_RNGP_XMLNS_NAME,
05309                        "Attribute with QName 'xmlns' is not allowed\n",
05310                        val, NULL);
05311         }
05312     } else if (IS_RELAXNG(node, "anyName")) {
05313         ret->name = NULL;
05314         ret->ns = NULL;
05315         if (node->children != NULL) {
05316             ret->nameClass =
05317                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
05318                                                (def->type ==
05319                                                 XML_RELAXNG_ATTRIBUTE));
05320         }
05321     } else if (IS_RELAXNG(node, "nsName")) {
05322         ret->name = NULL;
05323         ret->ns = xmlGetProp(node, BAD_CAST "ns");
05324         if (ret->ns == NULL) {
05325             xmlRngPErr(ctxt, node, XML_RNGP_NSNAME_NO_NS,
05326                        "nsName has no ns attribute\n", NULL, NULL);
05327         }
05328         if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
05329             (ret->ns != NULL) &&
05330             (xmlStrEqual
05331              (ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
05332             xmlRngPErr(ctxt, node, XML_RNGP_XML_NS,
05333                        "Attribute with namespace '%s' is not allowed\n",
05334                        ret->ns, NULL);
05335         }
05336         if (node->children != NULL) {
05337             ret->nameClass =
05338                 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
05339                                                (def->type ==
05340                                                 XML_RELAXNG_ATTRIBUTE));
05341         }
05342     } else if (IS_RELAXNG(node, "choice")) {
05343         xmlNodePtr child;
05344         xmlRelaxNGDefinePtr last = NULL;
05345 
05346         ret = xmlRelaxNGNewDefine(ctxt, node);
05347         if (ret == NULL)
05348             return (NULL);
05349         ret->parent = def;
05350         ret->type = XML_RELAXNG_CHOICE;
05351 
05352         if (node->children == NULL) {
05353             xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_EMPTY,
05354                        "Element choice is empty\n", NULL, NULL);
05355         } else {
05356 
05357             child = node->children;
05358             while (child != NULL) {
05359                 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
05360                 if (tmp != NULL) {
05361                     if (last == NULL) {
05362                         last = ret->nameClass = tmp;
05363                     } else {
05364                         last->next = tmp;
05365                         last = tmp;
05366                     }
05367                 }
05368                 child = child->next;
05369             }
05370         }
05371     } else {
05372         xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
05373                    "expecting name, anyName, nsName or choice : got %s\n",
05374                    (node == NULL ? (const xmlChar *) "nothing" : node->name),
05375            NULL);
05376         return (NULL);
05377     }
05378     if (ret != def) {
05379         if (def->nameClass == NULL) {
05380             def->nameClass = ret;
05381         } else {
05382             tmp = def->nameClass;
05383             while (tmp->next != NULL) {
05384                 tmp = tmp->next;
05385             }
05386             tmp->next = ret;
05387         }
05388     }
05389     return (ret);
05390 }
05391 
05392 /**
05393  * xmlRelaxNGParseElement:
05394  * @ctxt:  a Relax-NG parser context
05395  * @node:  the element node
05396  *
05397  * parse the content of a RelaxNG element node.
05398  *
05399  * Returns the definition pointer or NULL in case of error.
05400  */
05401 static xmlRelaxNGDefinePtr
05402 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
05403 {
05404     xmlRelaxNGDefinePtr ret, cur, last;
05405     xmlNodePtr child;
05406     const xmlChar *olddefine;
05407 
05408     ret = xmlRelaxNGNewDefine(ctxt, node);
05409     if (ret == NULL)
05410         return (NULL);
05411     ret->type = XML_RELAXNG_ELEMENT;
05412     ret->parent = ctxt->def;
05413     child = node->children;
05414     if (child == NULL) {
05415         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_EMPTY,
05416                    "xmlRelaxNGParseElement: element has no children\n",
05417                    NULL, NULL);
05418         return (ret);
05419     }
05420     cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
05421     if (cur != NULL)
05422         child = child->next;
05423 
05424     if (child == NULL) {
05425         xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_NO_CONTENT,
05426                    "xmlRelaxNGParseElement: element has no content\n",
05427                    NULL, NULL);
05428         return (ret);
05429     }
05430     olddefine = ctxt->define;
05431     ctxt->define = NULL;
05432     last = NULL;
05433     while (child != NULL) {
05434         cur = xmlRelaxNGParsePattern(ctxt, child);
05435         if (cur != NULL) {
05436             cur->parent = ret;
05437             switch (cur->type) {
05438                 case XML_RELAXNG_EMPTY:
05439                 case XML_RELAXNG_NOT_ALLOWED:
05440                 case XML_RELAXNG_TEXT:
05441                 case XML_RELAXNG_ELEMENT:
05442                 case XML_RELAXNG_DATATYPE:
05443                 case XML_RELAXNG_VALUE:
05444                 case XML_RELAXNG_LIST:
05445                 case XML_RELAXNG_REF:
05446                 case XML_RELAXNG_PARENTREF:
05447                 case XML_RELAXNG_EXTERNALREF:
05448                 case XML_RELAXNG_DEF:
05449                 case XML_RELAXNG_ZEROORMORE:
05450                 case XML_RELAXNG_ONEORMORE:
05451                 case XML_RELAXNG_OPTIONAL:
05452                 case XML_RELAXNG_CHOICE:
05453                 case XML_RELAXNG_GROUP:
05454                 case XML_RELAXNG_INTERLEAVE:
05455                     if (last == NULL) {
05456                         ret->content = last = cur;
05457                     } else {
05458                         if ((last->type == XML_RELAXNG_ELEMENT) &&
05459                             (ret->content == last)) {
05460                             ret->content = xmlRelaxNGNewDefine(ctxt, node);
05461                             if (ret->content != NULL) {
05462                                 ret->content->type = XML_RELAXNG_GROUP;
05463                                 ret->content->content = last;
05464                             } else {
05465                                 ret->content = last;
05466                             }
05467                         }
05468                         last->next = cur;
05469                         last = cur;
05470                     }
05471                     break;
05472                 case XML_RELAXNG_ATTRIBUTE:
05473                     cur->next = ret->attrs;
05474                     ret->attrs = cur;
05475                     break;
05476                 case XML_RELAXNG_START:
05477                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
05478                                "RNG Internal error, start found in element\n",
05479                                NULL, NULL);
05480                     break;
05481                 case XML_RELAXNG_PARAM:
05482                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
05483                                "RNG Internal error, param found in element\n",
05484                                NULL, NULL);
05485                     break;
05486                 case XML_RELAXNG_EXCEPT:
05487                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
05488                                "RNG Internal error, except found in element\n",
05489                                NULL, NULL);
05490                     break;
05491                 case XML_RELAXNG_NOOP:
05492                     xmlRngPErr(ctxt, node, XML_RNGP_ELEMENT_CONTENT,
05493                                "RNG Internal error, noop found in element\n",
05494                                NULL, NULL);
05495                     break;
05496             }
05497         }
05498         child = child->next;
05499     }
05500     ctxt->define = olddefine;
05501     return (ret);
05502 }
05503 
05504 /**
05505  * xmlRelaxNGParsePatterns:
05506  * @ctxt:  a Relax-NG parser context
05507  * @nodes:  list of nodes
05508  * @group:  use an implicit <group> for elements
05509  *
05510  * parse the content of a RelaxNG start node.
05511  *
05512  * Returns the definition pointer or NULL in case of error.
05513  */
05514 static xmlRelaxNGDefinePtr
05515 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
05516                         int group)
05517 {
05518     xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
05519 
05520     parent = ctxt->def;
05521     while (nodes != NULL) {
05522         if (IS_RELAXNG(nodes, "element")) {
05523             cur = xmlRelaxNGParseElement(ctxt, nodes);
05524             if (def == NULL) {
05525                 def = last = cur;
05526             } else {
05527                 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
05528                     (def == last)) {
05529                     def = xmlRelaxNGNewDefine(ctxt, nodes);
05530                     def->type = XML_RELAXNG_GROUP;
05531                     def->content = last;
05532                 }
05533                 last->next = cur;
05534                 last = cur;
05535             }
05536             cur->parent = parent;
05537         } else {
05538             cur = xmlRelaxNGParsePattern(ctxt, nodes);
05539             if (cur != NULL) {
05540                 if (def == NULL) {
05541                     def = last = cur;
05542                 } else {
05543                     last->next = cur;
05544                     last = cur;
05545                 }
05546             }
05547         }
05548         nodes = nodes->next;
05549     }
05550     return (def);
05551 }
05552 
05553 /**
05554  * xmlRelaxNGParseStart:
05555  * @ctxt:  a Relax-NG parser context
05556  * @nodes:  start children nodes
05557  *
05558  * parse the content of a RelaxNG start node.
05559  *
05560  * Returns 0 in case of success, -1 in case of error
05561  */
05562 static int
05563 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
05564 {
05565     int ret = 0;
05566     xmlRelaxNGDefinePtr def = NULL, last;
05567 
05568     if (nodes == NULL) {
05569         xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY, "start has no children\n",
05570                    NULL, NULL);
05571         return (-1);
05572     }
05573     if (IS_RELAXNG(nodes, "empty")) {
05574         def = xmlRelaxNGNewDefine(ctxt, nodes);
05575         if (def == NULL)
05576             return (-1);
05577         def->type = XML_RELAXNG_EMPTY;
05578         if (nodes->children != NULL) {
05579             xmlRngPErr(ctxt, nodes, XML_RNGP_EMPTY_CONTENT,
05580                        "element empty is not empty\n", NULL, NULL);
05581         }
05582     } else if (IS_RELAXNG(nodes, "notAllowed")) {
05583         def = xmlRelaxNGNewDefine(ctxt, nodes);
05584         if (def == NULL)
05585             return (-1);
05586         def->type = XML_RELAXNG_NOT_ALLOWED;
05587         if (nodes->children != NULL) {
05588             xmlRngPErr(ctxt, nodes, XML_RNGP_NOTALLOWED_NOT_EMPTY,
05589                        "element notAllowed is not empty\n", NULL, NULL);
05590         }
05591     } else {
05592         def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
05593     }
05594     if (ctxt->grammar->start != NULL) {
05595         last = ctxt->grammar->start;
05596         while (last->next != NULL)
05597             last = last->next;
05598         last->next = def;
05599     } else {
05600         ctxt->grammar->start = def;
05601     }
05602     nodes = nodes->next;
05603     if (nodes != NULL) {
05604         xmlRngPErr(ctxt, nodes, XML_RNGP_START_CONTENT,
05605                    "start more than one children\n", NULL, NULL);
05606         return (-1);
05607     }
05608     return (ret);
05609 }
05610 
05611 /**
05612  * xmlRelaxNGParseGrammarContent:
05613  * @ctxt:  a Relax-NG parser context
05614  * @nodes:  grammar children nodes
05615  *
05616  * parse the content of a RelaxNG grammar node.
05617  *
05618  * Returns 0 in case of success, -1 in case of error
05619  */
05620 static int
05621 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt,
05622                               xmlNodePtr nodes)
05623 {
05624     int ret = 0, tmp;
05625 
05626     if (nodes == NULL) {
05627         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_EMPTY,
05628                    "grammar has no children\n", NULL, NULL);
05629         return (-1);
05630     }
05631     while (nodes != NULL) {
05632         if (IS_RELAXNG(nodes, "start")) {
05633             if (nodes->children == NULL) {
05634                 xmlRngPErr(ctxt, nodes, XML_RNGP_START_EMPTY,
05635                            "start has no children\n", NULL, NULL);
05636             } else {
05637                 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
05638                 if (tmp != 0)
05639                     ret = -1;
05640             }
05641         } else if (IS_RELAXNG(nodes, "define")) {
05642             tmp = xmlRelaxNGParseDefine(ctxt, nodes);
05643             if (tmp != 0)
05644                 ret = -1;
05645         } else if (IS_RELAXNG(nodes, "include")) {
05646             tmp = xmlRelaxNGParseInclude(ctxt, nodes);
05647             if (tmp != 0)
05648                 ret = -1;
05649         } else {
05650             xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
05651                        "grammar has unexpected child %s\n", nodes->name,
05652                        NULL);
05653             ret = -1;
05654         }
05655         nodes = nodes->next;
05656     }
05657     return (ret);
05658 }
05659 
05660 /**
05661  * xmlRelaxNGCheckReference:
05662  * @ref:  the ref
05663  * @ctxt:  a Relax-NG parser context
05664  * @name:  the name associated to the defines
05665  *
05666  * Applies the 4.17. combine attribute rule for all the define
05667  * element of a given grammar using the same name.
05668  */
05669 static void
05670 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
05671                          xmlRelaxNGParserCtxtPtr ctxt,
05672                          const xmlChar * name)
05673 {
05674     xmlRelaxNGGrammarPtr grammar;
05675     xmlRelaxNGDefinePtr def, cur;
05676 
05677     /*
05678      * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
05679      */
05680     if (ref->dflags & IS_EXTERNAL_REF)
05681         return;
05682 
05683     grammar = ctxt->grammar;
05684     if (grammar == NULL) {
05685         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
05686                    "Internal error: no grammar in CheckReference %s\n",
05687                    name, NULL);
05688         return;
05689     }
05690     if (ref->content != NULL) {
05691         xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
05692                    "Internal error: reference has content in CheckReference %s\n",
05693                    name, NULL);
05694         return;
05695     }
05696     if (grammar->defs != NULL) {
05697         def = xmlHashLookup(grammar->defs, name);
05698         if (def != NULL) {
05699             cur = ref;
05700             while (cur != NULL) {
05701                 cur->content = def;
05702                 cur = cur->nextHash;
05703             }
05704         } else {
05705             xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
05706                        "Reference %s has no matching definition\n", name,
05707                        NULL);
05708         }
05709     } else {
05710         xmlRngPErr(ctxt, ref->node, XML_RNGP_REF_NO_DEF,
05711                    "Reference %s has no matching definition\n", name,
05712                    NULL);
05713     }
05714 }
05715 
05716 /**
05717  * xmlRelaxNGCheckCombine:
05718  * @define:  the define(s) list
05719  * @ctxt:  a Relax-NG parser context
05720  * @name:  the name associated to the defines
05721  *
05722  * Applies the 4.17. combine attribute rule for all the define
05723  * element of a given grammar using the same name.
05724  */
05725 static void
05726 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
05727                        xmlRelaxNGParserCtxtPtr ctxt, const xmlChar * name)
05728 {
05729     xmlChar *combine;
05730     int choiceOrInterleave = -1;
05731     int missing = 0;
05732     xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
05733 
05734     if (define->nextHash == NULL)
05735         return;
05736     cur = define;
05737     while (cur != NULL) {
05738         combine = xmlGetProp(cur->node, BAD_CAST "combine");
05739         if (combine != NULL) {
05740             if (xmlStrEqual(combine, BAD_CAST "choice")) {
05741                 if (choiceOrInterleave == -1)
05742                     choiceOrInterleave = 1;
05743                 else if (choiceOrInterleave == 0) {
05744                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
05745                                "Defines for %s use both 'choice' and 'interleave'\n",
05746                                name, NULL);
05747                 }
05748             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
05749                 if (choiceOrInterleave == -1)
05750                     choiceOrInterleave = 0;
05751                 else if (choiceOrInterleave == 1) {
05752                     xmlRngPErr(ctxt, define->node, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE,
05753                                "Defines for %s use both 'choice' and 'interleave'\n",
05754                                name, NULL);
05755                 }
05756             } else {
05757                 xmlRngPErr(ctxt, define->node, XML_RNGP_UNKNOWN_COMBINE,
05758                            "Defines for %s use unknown combine value '%s''\n",
05759                            name, combine);
05760             }
05761             xmlFree(combine);
05762         } else {
05763             if (missing == 0)
05764                 missing = 1;
05765             else {
05766                 xmlRngPErr(ctxt, define->node, XML_RNGP_NEED_COMBINE,
05767                            "Some defines for %s needs the combine attribute\n",
05768                            name, NULL);
05769             }
05770         }
05771 
05772         cur = cur->nextHash;
05773     }
05774 #ifdef DEBUG
05775     xmlGenericError(xmlGenericErrorContext,
05776                     "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
05777                     name, choiceOrInterleave);
05778 #endif
05779     if (choiceOrInterleave == -1)
05780         choiceOrInterleave = 0;
05781     cur = xmlRelaxNGNewDefine(ctxt, define->node);
05782     if (cur == NULL)
05783         return;
05784     if (choiceOrInterleave == 0)
05785         cur->type = XML_RELAXNG_INTERLEAVE;
05786     else
05787         cur->type = XML_RELAXNG_CHOICE;
05788     tmp = define;
05789     last = NULL;
05790     while (tmp != NULL) {
05791         if (tmp->content != NULL) {
05792             if (tmp->content->next != NULL) {
05793                 /*
05794                  * we need first to create a wrapper.
05795                  */
05796                 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
05797                 if (tmp2 == NULL)
05798                     break;
05799                 tmp2->type = XML_RELAXNG_GROUP;
05800                 tmp2->content = tmp->content;
05801             } else {
05802                 tmp2 = tmp->content;
05803             }
05804             if (last == NULL) {
05805                 cur->content = tmp2;
05806             } else {
05807                 last->next = tmp2;
05808             }
05809             last = tmp2;
05810         }
05811         tmp->content = cur;
05812         tmp = tmp->nextHash;
05813     }
05814     define->content = cur;
05815     if (choiceOrInterleave == 0) {
05816         if (ctxt->interleaves == NULL)
05817             ctxt->interleaves = xmlHashCreate(10);
05818         if (ctxt->interleaves == NULL) {
05819             xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
05820                        "Failed to create interleaves hash table\n", NULL,
05821                        NULL);
05822         } else {
05823             char tmpname[32];
05824 
05825             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
05826             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
05827                 0) {
05828                 xmlRngPErr(ctxt, define->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
05829                            "Failed to add %s to hash table\n",
05830                (const xmlChar *) tmpname, NULL);
05831             }
05832         }
05833     }
05834 }
05835 
05836 /**
05837  * xmlRelaxNGCombineStart:
05838  * @ctxt:  a Relax-NG parser context
05839  * @grammar:  the grammar
05840  *
05841  * Applies the 4.17. combine rule for all the start
05842  * element of a given grammar.
05843  */
05844 static void
05845 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
05846                        xmlRelaxNGGrammarPtr grammar)
05847 {
05848     xmlRelaxNGDefinePtr starts;
05849     xmlChar *combine;
05850     int choiceOrInterleave = -1;
05851     int missing = 0;
05852     xmlRelaxNGDefinePtr cur;
05853 
05854     starts = grammar->start;
05855     if ((starts == NULL) || (starts->next == NULL))
05856         return;
05857     cur = starts;
05858     while (cur != NULL) {
05859         if ((cur->node == NULL) || (cur->node->parent == NULL) ||
05860             (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
05861             combine = NULL;
05862             xmlRngPErr(ctxt, cur->node, XML_RNGP_START_MISSING,
05863                        "Internal error: start element not found\n", NULL,
05864                        NULL);
05865         } else {
05866             combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
05867         }
05868 
05869         if (combine != NULL) {
05870             if (xmlStrEqual(combine, BAD_CAST "choice")) {
05871                 if (choiceOrInterleave == -1)
05872                     choiceOrInterleave = 1;
05873                 else if (choiceOrInterleave == 0) {
05874                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
05875                                "<start> use both 'choice' and 'interleave'\n",
05876                                NULL, NULL);
05877                 }
05878             } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
05879                 if (choiceOrInterleave == -1)
05880                     choiceOrInterleave = 0;
05881                 else if (choiceOrInterleave == 1) {
05882                     xmlRngPErr(ctxt, cur->node, XML_RNGP_START_CHOICE_AND_INTERLEAVE,
05883                                "<start> use both 'choice' and 'interleave'\n",
05884                                NULL, NULL);
05885                 }
05886             } else {
05887                 xmlRngPErr(ctxt, cur->node, XML_RNGP_UNKNOWN_COMBINE,
05888                            "<start> uses unknown combine value '%s''\n",
05889                            combine, NULL);
05890             }
05891             xmlFree(combine);
05892         } else {
05893             if (missing == 0)
05894                 missing = 1;
05895             else {
05896                 xmlRngPErr(ctxt, cur->node, XML_RNGP_NEED_COMBINE,
05897                            "Some <start> element miss the combine attribute\n",
05898                            NULL, NULL);
05899             }
05900         }
05901 
05902         cur = cur->next;
05903     }
05904 #ifdef DEBUG
05905     xmlGenericError(xmlGenericErrorContext,
05906                     "xmlRelaxNGCombineStart(): merging <start>: %d\n",
05907                     choiceOrInterleave);
05908 #endif
05909     if (choiceOrInterleave == -1)
05910         choiceOrInterleave = 0;
05911     cur = xmlRelaxNGNewDefine(ctxt, starts->node);
05912     if (cur == NULL)
05913         return;
05914     if (choiceOrInterleave == 0)
05915         cur->type = XML_RELAXNG_INTERLEAVE;
05916     else
05917         cur->type = XML_RELAXNG_CHOICE;
05918     cur->content = grammar->start;
05919     grammar->start = cur;
05920     if (choiceOrInterleave == 0) {
05921         if (ctxt->interleaves == NULL)
05922             ctxt->interleaves = xmlHashCreate(10);
05923         if (ctxt->interleaves == NULL) {
05924             xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
05925                        "Failed to create interleaves hash table\n", NULL,
05926                        NULL);
05927         } else {
05928             char tmpname[32];
05929 
05930             snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
05931             if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) <
05932                 0) {
05933                 xmlRngPErr(ctxt, cur->node, XML_RNGP_INTERLEAVE_CREATE_FAILED,
05934                            "Failed to add %s to hash table\n",
05935                (const xmlChar *) tmpname, NULL);
05936             }
05937         }
05938     }
05939 }
05940 
05941 /**
05942  * xmlRelaxNGCheckCycles:
05943  * @ctxt:  a Relax-NG parser context
05944  * @nodes:  grammar children nodes
05945  * @depth:  the counter
05946  *
05947  * Check for cycles.
05948  *
05949  * Returns 0 if check passed, and -1 in case of error
05950  */
05951 static int
05952 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
05953                       xmlRelaxNGDefinePtr cur, int depth)
05954 {
05955     int ret = 0;
05956 
05957     while ((ret == 0) && (cur != NULL)) {
05958         if ((cur->type == XML_RELAXNG_REF) ||
05959             (cur->type == XML_RELAXNG_PARENTREF)) {
05960             if (cur->depth == -1) {
05961                 cur->depth = depth;
05962                 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
05963                 cur->depth = -2;
05964             } else if (depth == cur->depth) {
05965                 xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_CYCLE,
05966                            "Detected a cycle in %s references\n",
05967                            cur->name, NULL);
05968                 return (-1);
05969             }
05970         } else if (cur->type == XML_RELAXNG_ELEMENT) {
05971             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
05972         } else {
05973             ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
05974         }
05975         cur = cur->next;
05976     }
05977     return (ret);
05978 }
05979 
05980 /**
05981  * xmlRelaxNGTryUnlink:
05982  * @ctxt:  a Relax-NG parser context
05983  * @cur:  the definition to unlink
05984  * @parent:  the parent definition
05985  * @prev:  the previous sibling definition
05986  *
05987  * Try to unlink a definition. If not possble make it a NOOP
05988  *
05989  * Returns the new prev definition
05990  */
05991 static xmlRelaxNGDefinePtr
05992 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
05993                     xmlRelaxNGDefinePtr cur,
05994                     xmlRelaxNGDefinePtr parent, xmlRelaxNGDefinePtr prev)
05995 {
05996     if (prev != NULL) {
05997         prev->next = cur->next;
05998     } else {
05999         if (parent != NULL) {
06000             if (parent->content == cur)
06001                 parent->content = cur->next;
06002             else if (parent->attrs == cur)
06003                 parent->attrs = cur->next;
06004             else if (parent->nameClass == cur)
06005                 parent->nameClass = cur->next;
06006         } else {
06007             cur->type = XML_RELAXNG_NOOP;
06008             prev = cur;
06009         }
06010     }
06011     return (prev);
06012 }
06013 
06014 /**
06015  * xmlRelaxNGSimplify:
06016  * @ctxt:  a Relax-NG parser context
06017  * @nodes:  grammar children nodes
06018  *
06019  * Check for simplification of empty and notAllowed
06020  */
06021 static void
06022 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
06023                    xmlRelaxNGDefinePtr cur, xmlRelaxNGDefinePtr parent)
06024 {
06025     xmlRelaxNGDefinePtr prev = NULL;
06026 
06027     while (cur != NULL) {
06028         if ((cur->type == XML_RELAXNG_REF) ||
06029             (cur->type == XML_RELAXNG_PARENTREF)) {
06030             if (cur->depth != -3) {
06031                 cur->depth = -3;
06032                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
06033             }
06034         } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
06035             cur->parent = parent;
06036             if ((parent != NULL) &&
06037                 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
06038                  (parent->type == XML_RELAXNG_LIST) ||
06039                  (parent->type == XML_RELAXNG_GROUP) ||
06040                  (parent->type == XML_RELAXNG_INTERLEAVE) ||
06041                  (parent->type == XML_RELAXNG_ONEORMORE) ||
06042                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
06043                 parent->type = XML_RELAXNG_NOT_ALLOWED;
06044                 break;
06045             }
06046             if ((parent != NULL) && (parent->type == XML_RELAXNG_CHOICE)) {
06047                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
06048             } else
06049                 prev = cur;
06050         } else if (cur->type == XML_RELAXNG_EMPTY) {
06051             cur->parent = parent;
06052             if ((parent != NULL) &&
06053                 ((parent->type == XML_RELAXNG_ONEORMORE) ||
06054                  (parent->type == XML_RELAXNG_ZEROORMORE))) {
06055                 parent->type = XML_RELAXNG_EMPTY;
06056                 break;
06057             }
06058             if ((parent != NULL) &&
06059                 ((parent->type == XML_RELAXNG_GROUP) ||
06060                  (parent->type == XML_RELAXNG_INTERLEAVE))) {
06061                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
06062             } else
06063                 prev = cur;
06064         } else {
06065             cur->parent = parent;
06066             if (cur->content != NULL)
06067                 xmlRelaxNGSimplify(ctxt, cur->content, cur);
06068             if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
06069                 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
06070             if (cur->nameClass != NULL)
06071                 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
06072             /*
06073              * On Elements, try to move attribute only generating rules on
06074              * the attrs rules.
06075              */
06076             if (cur->type == XML_RELAXNG_ELEMENT) {
06077                 int attronly;
06078                 xmlRelaxNGDefinePtr tmp, pre;
06079 
06080                 while (cur->content != NULL) {
06081                     attronly =
06082                         xmlRelaxNGGenerateAttributes(ctxt, cur->content);
06083                     if (attronly == 1) {
06084                         /*
06085                          * migrate cur->content to attrs
06086                          */
06087                         tmp = cur->content;
06088                         cur->content = tmp->next;
06089                         tmp->next = cur->attrs;
06090                         cur->attrs = tmp;
06091                     } else {
06092                         /*
06093                          * cur->content can generate elements or text
06094                          */
06095                         break;
06096                     }
06097                 }
06098                 pre = cur->content;
06099                 while ((pre != NULL) && (pre->next != NULL)) {
06100                     tmp = pre->next;
06101                     attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
06102                     if (attronly == 1) {
06103                         /*
06104                          * migrate tmp to attrs
06105                          */
06106                         pre->next = tmp->next;
06107                         tmp->next = cur->attrs;
06108                         cur->attrs = tmp;
06109                     } else {
06110                         pre = tmp;
06111                     }
06112                 }
06113             }
06114             /*
06115              * This may result in a simplification
06116              */
06117             if ((cur->type == XML_RELAXNG_GROUP) ||
06118                 (cur->type == XML_RELAXNG_INTERLEAVE)) {
06119                 if (cur->content == NULL)
06120                     cur->type = XML_RELAXNG_EMPTY;
06121                 else if (cur->content->next == NULL) {
06122                     if ((parent == NULL) && (prev == NULL)) {
06123                         cur->type = XML_RELAXNG_NOOP;
06124                     } else if (prev == NULL) {
06125                         parent->content = cur->content;
06126                         cur->content->next = cur->next;
06127                         cur = cur->content;
06128                     } else {
06129                         cur->content->next = cur->next;
06130                         prev->next = cur->content;
06131                         cur = cur->content;
06132                     }
06133                 }
06134             }
06135             /*
06136              * the current node may have been transformed back
06137              */
06138             if ((cur->type == XML_RELAXNG_EXCEPT) &&
06139                 (cur->content != NULL) &&
06140                 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
06141                 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
06142             } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
06143                 if ((parent != NULL) &&
06144                     ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
06145                      (parent->type == XML_RELAXNG_LIST) ||
06146                      (parent->type == XML_RELAXNG_GROUP) ||
06147                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
06148                      (parent->type == XML_RELAXNG_ONEORMORE) ||
06149                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
06150                     parent->type = XML_RELAXNG_NOT_ALLOWED;
06151                     break;
06152                 }
06153                 if ((parent != NULL) &&
06154                     (parent->type == XML_RELAXNG_CHOICE)) {
06155                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
06156                 } else
06157                     prev = cur;
06158             } else if (cur->type == XML_RELAXNG_EMPTY) {
06159                 if ((parent != NULL) &&
06160                     ((parent->type == XML_RELAXNG_ONEORMORE) ||
06161                      (parent->type == XML_RELAXNG_ZEROORMORE))) {
06162                     parent->type = XML_RELAXNG_EMPTY;
06163                     break;
06164                 }
06165                 if ((parent != NULL) &&
06166                     ((parent->type == XML_RELAXNG_GROUP) ||
06167                      (parent->type == XML_RELAXNG_INTERLEAVE) ||
06168                      (parent->type == XML_RELAXNG_CHOICE))) {
06169                     prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
06170                 } else
06171                     prev = cur;
06172             } else {
06173                 prev = cur;
06174             }
06175         }
06176         cur = cur->next;
06177     }
06178 }
06179 
06180 /**
06181  * xmlRelaxNGGroupContentType:
06182  * @ct1:  the first content type
06183  * @ct2:  the second content type
06184  *
06185  * Try to group 2 content types
06186  *
06187  * Returns the content type
06188  */
06189 static xmlRelaxNGContentType
06190 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
06191                            xmlRelaxNGContentType ct2)
06192 {
06193     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
06194         (ct2 == XML_RELAXNG_CONTENT_ERROR))
06195         return (XML_RELAXNG_CONTENT_ERROR);
06196     if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
06197         return (ct2);
06198     if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
06199         return (ct1);
06200     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
06201         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
06202         return (XML_RELAXNG_CONTENT_COMPLEX);
06203     return (XML_RELAXNG_CONTENT_ERROR);
06204 }
06205 
06206 /**
06207  * xmlRelaxNGMaxContentType:
06208  * @ct1:  the first content type
06209  * @ct2:  the second content type
06210  *
06211  * Compute the max content-type
06212  *
06213  * Returns the content type
06214  */
06215 static xmlRelaxNGContentType
06216 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
06217                          xmlRelaxNGContentType ct2)
06218 {
06219     if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
06220         (ct2 == XML_RELAXNG_CONTENT_ERROR))
06221         return (XML_RELAXNG_CONTENT_ERROR);
06222     if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
06223         (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
06224         return (XML_RELAXNG_CONTENT_SIMPLE);
06225     if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
06226         (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
06227         return (XML_RELAXNG_CONTENT_COMPLEX);
06228     return (XML_RELAXNG_CONTENT_EMPTY);
06229 }
06230 
06231 /**
06232  * xmlRelaxNGCheckRules:
06233  * @ctxt:  a Relax-NG parser context
06234  * @cur:  the current definition
06235  * @flags:  some accumulated flags
06236  * @ptype:  the parent type
06237  *
06238  * Check for rules in section 7.1 and 7.2
06239  *
06240  * Returns the content type of @cur
06241  */
06242 static xmlRelaxNGContentType
06243 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
06244                      xmlRelaxNGDefinePtr cur, int flags,
06245                      xmlRelaxNGType ptype)
06246 {
06247     int nflags;
06248     xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
06249 
06250     while (cur != NULL) {
06251         ret = XML_RELAXNG_CONTENT_EMPTY;
06252         if ((cur->type == XML_RELAXNG_REF) ||
06253             (cur->type == XML_RELAXNG_PARENTREF)) {
06254            /*
06255             * This should actually be caught by list//element(ref) at the
06256             * element boundaries, c.f. Bug #159968 local refs are dropped
06257             * in step 4.19.
06258             */
06259 #if 0
06260             if (flags & XML_RELAXNG_IN_LIST) {
06261                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_REF,
06262                            "Found forbidden pattern list//ref\n", NULL,
06263                            NULL);
06264             }
06265 #endif
06266             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06267                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_REF,
06268                            "Found forbidden pattern data/except//ref\n",
06269                            NULL, NULL);
06270             }
06271             if (cur->content == NULL) {
06272                 if (cur->type == XML_RELAXNG_PARENTREF)
06273                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
06274                                "Internal found no define for parent refs\n",
06275                                NULL, NULL);
06276                 else
06277                     xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
06278                                "Internal found no define for ref %s\n",
06279                                (cur->name ? cur->name: BAD_CAST "null"), NULL);
06280             }
06281             if (cur->depth > -4) {
06282                 cur->depth = -4;
06283                 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
06284                                            flags, cur->type);
06285                 cur->depth = ret - 15;
06286             } else if (cur->depth == -4) {
06287                 ret = XML_RELAXNG_CONTENT_COMPLEX;
06288             } else {
06289                 ret = (xmlRelaxNGContentType) (cur->depth + 15);
06290             }
06291         } else if (cur->type == XML_RELAXNG_ELEMENT) {
06292             /*
06293              * The 7.3 Attribute derivation rule for groups is plugged there
06294              */
06295             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
06296             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06297                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ELEM,
06298                            "Found forbidden pattern data/except//element(ref)\n",
06299                            NULL, NULL);
06300             }
06301             if (flags & XML_RELAXNG_IN_LIST) {
06302                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ELEM,
06303                            "Found forbidden pattern list//element(ref)\n",
06304                            NULL, NULL);
06305             }
06306             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
06307                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
06308                            "Found forbidden pattern attribute//element(ref)\n",
06309                            NULL, NULL);
06310             }
06311             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
06312                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ELEM,
06313                            "Found forbidden pattern attribute//element(ref)\n",
06314                            NULL, NULL);
06315             }
06316             /*
06317              * reset since in the simple form elements are only child
06318              * of grammar/define
06319              */
06320             nflags = 0;
06321             ret =
06322                 xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
06323             if (ret != XML_RELAXNG_CONTENT_EMPTY) {
06324                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_EMPTY,
06325                            "Element %s attributes have a content type error\n",
06326                            cur->name, NULL);
06327             }
06328             ret =
06329                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
06330                                      cur->type);
06331             if (ret == XML_RELAXNG_CONTENT_ERROR) {
06332                 xmlRngPErr(ctxt, cur->node, XML_RNGP_ELEM_CONTENT_ERROR,
06333                            "Element %s has a content type error\n",
06334                            cur->name, NULL);
06335             } else {
06336                 ret = XML_RELAXNG_CONTENT_COMPLEX;
06337             }
06338         } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
06339             if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
06340                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ATTR_ATTR,
06341                            "Found forbidden pattern attribute//attribute\n",
06342                            NULL, NULL);
06343             }
06344             if (flags & XML_RELAXNG_IN_LIST) {
06345                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_ATTR,
06346                            "Found forbidden pattern list//attribute\n",
06347                            NULL, NULL);
06348             }
06349             if (flags & XML_RELAXNG_IN_OOMGROUP) {
06350                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_GROUP_ATTR,
06351                            "Found forbidden pattern oneOrMore//group//attribute\n",
06352                            NULL, NULL);
06353             }
06354             if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
06355                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR,
06356                            "Found forbidden pattern oneOrMore//interleave//attribute\n",
06357                            NULL, NULL);
06358             }
06359             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06360                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ATTR,
06361                            "Found forbidden pattern data/except//attribute\n",
06362                            NULL, NULL);
06363             }
06364             if (flags & XML_RELAXNG_IN_START) {
06365                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ATTR,
06366                            "Found forbidden pattern start//attribute\n",
06367                            NULL, NULL);
06368             }
06369             if ((!(flags & XML_RELAXNG_IN_ONEORMORE))
06370                 && (cur->name == NULL)) {
06371                 if (cur->ns == NULL) {
06372                     xmlRngPErr(ctxt, cur->node, XML_RNGP_ANYNAME_ATTR_ANCESTOR,
06373                                "Found anyName attribute without oneOrMore ancestor\n",
06374                                NULL, NULL);
06375                 } else {
06376                     xmlRngPErr(ctxt, cur->node, XML_RNGP_NSNAME_ATTR_ANCESTOR,
06377                                "Found nsName attribute without oneOrMore ancestor\n",
06378                                NULL, NULL);
06379                 }
06380             }
06381             nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
06382             xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
06383             ret = XML_RELAXNG_CONTENT_EMPTY;
06384         } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
06385                    (cur->type == XML_RELAXNG_ZEROORMORE)) {
06386             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06387                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE,
06388                            "Found forbidden pattern data/except//oneOrMore\n",
06389                            NULL, NULL);
06390             }
06391             if (flags & XML_RELAXNG_IN_START) {
06392                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_ONEMORE,
06393                            "Found forbidden pattern start//oneOrMore\n",
06394                            NULL, NULL);
06395             }
06396             nflags = flags | XML_RELAXNG_IN_ONEORMORE;
06397             ret =
06398                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
06399                                      cur->type);
06400             ret = xmlRelaxNGGroupContentType(ret, ret);
06401         } else if (cur->type == XML_RELAXNG_LIST) {
06402             if (flags & XML_RELAXNG_IN_LIST) {
06403                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_LIST,
06404                            "Found forbidden pattern list//list\n", NULL,
06405                            NULL);
06406             }
06407             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06408                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_LIST,
06409                            "Found forbidden pattern data/except//list\n",
06410                            NULL, NULL);
06411             }
06412             if (flags & XML_RELAXNG_IN_START) {
06413                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_LIST,
06414                            "Found forbidden pattern start//list\n", NULL,
06415                            NULL);
06416             }
06417             nflags = flags | XML_RELAXNG_IN_LIST;
06418             ret =
06419                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
06420                                      cur->type);
06421         } else if (cur->type == XML_RELAXNG_GROUP) {
06422             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06423                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_GROUP,
06424                            "Found forbidden pattern data/except//group\n",
06425                            NULL, NULL);
06426             }
06427             if (flags & XML_RELAXNG_IN_START) {
06428                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_GROUP,
06429                            "Found forbidden pattern start//group\n", NULL,
06430                            NULL);
06431             }
06432             if (flags & XML_RELAXNG_IN_ONEORMORE)
06433                 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
06434             else
06435                 nflags = flags;
06436             ret =
06437                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
06438                                      cur->type);
06439             /*
06440              * The 7.3 Attribute derivation rule for groups is plugged there
06441              */
06442             xmlRelaxNGCheckGroupAttrs(ctxt, cur);
06443         } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
06444             if (flags & XML_RELAXNG_IN_LIST) {
06445                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_INTERLEAVE,
06446                            "Found forbidden pattern list//interleave\n",
06447                            NULL, NULL);
06448             }
06449             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06450                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
06451                            "Found forbidden pattern data/except//interleave\n",
06452                            NULL, NULL);
06453             }
06454             if (flags & XML_RELAXNG_IN_START) {
06455                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE,
06456                            "Found forbidden pattern start//interleave\n",
06457                            NULL, NULL);
06458             }
06459             if (flags & XML_RELAXNG_IN_ONEORMORE)
06460                 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
06461             else
06462                 nflags = flags;
06463             ret =
06464                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
06465                                      cur->type);
06466         } else if (cur->type == XML_RELAXNG_EXCEPT) {
06467             if ((cur->parent != NULL) &&
06468                 (cur->parent->type == XML_RELAXNG_DATATYPE))
06469                 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
06470             else
06471                 nflags = flags;
06472             ret =
06473                 xmlRelaxNGCheckRules(ctxt, cur->content, nflags,
06474                                      cur->type);
06475         } else if (cur->type == XML_RELAXNG_DATATYPE) {
06476             if (flags & XML_RELAXNG_IN_START) {
06477                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_DATA,
06478                            "Found forbidden pattern start//data\n", NULL,
06479                            NULL);
06480             }
06481             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
06482             ret = XML_RELAXNG_CONTENT_SIMPLE;
06483         } else if (cur->type == XML_RELAXNG_VALUE) {
06484             if (flags & XML_RELAXNG_IN_START) {
06485                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_VALUE,
06486                            "Found forbidden pattern start//value\n", NULL,
06487                            NULL);
06488             }
06489             xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
06490             ret = XML_RELAXNG_CONTENT_SIMPLE;
06491         } else if (cur->type == XML_RELAXNG_TEXT) {
06492             if (flags & XML_RELAXNG_IN_LIST) {
06493                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_LIST_TEXT,
06494                            "Found forbidden pattern list//text\n", NULL,
06495                            NULL);
06496             }
06497             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06498                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_TEXT,
06499                            "Found forbidden pattern data/except//text\n",
06500                            NULL, NULL);
06501             }
06502             if (flags & XML_RELAXNG_IN_START) {
06503                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_TEXT,
06504                            "Found forbidden pattern start//text\n", NULL,
06505                            NULL);
06506             }
06507             ret = XML_RELAXNG_CONTENT_COMPLEX;
06508         } else if (cur->type == XML_RELAXNG_EMPTY) {
06509             if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
06510                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_DATA_EXCEPT_EMPTY,
06511                            "Found forbidden pattern data/except//empty\n",
06512                            NULL, NULL);
06513             }
06514             if (flags & XML_RELAXNG_IN_START) {
06515                 xmlRngPErr(ctxt, cur->node, XML_RNGP_PAT_START_EMPTY,
06516                            "Found forbidden pattern start//empty\n", NULL,
06517                            NULL);
06518             }
06519             ret = XML_RELAXNG_CONTENT_EMPTY;
06520         } else if (cur->type == XML_RELAXNG_CHOICE) {
06521             xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
06522             ret =
06523                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
06524         } else {
06525             ret =
06526                 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
06527         }
06528         cur = cur->next;
06529         if (ptype == XML_RELAXNG_GROUP) {
06530             val = xmlRelaxNGGroupContentType(val, ret);
06531         } else if (ptype == XML_RELAXNG_INTERLEAVE) {
06532             /*
06533              * TODO: scan complain that tmp is never used, seems on purpose
06534              *       need double-checking
06535              */
06536             tmp = xmlRelaxNGGroupContentType(val, ret);
06537             if (tmp != XML_RELAXNG_CONTENT_ERROR)
06538                 tmp = xmlRelaxNGMaxContentType(val, ret);
06539         } else if (ptype == XML_RELAXNG_CHOICE) {
06540             val = xmlRelaxNGMaxContentType(val, ret);
06541         } else if (ptype == XML_RELAXNG_LIST) {
06542             val = XML_RELAXNG_CONTENT_SIMPLE;
06543         } else if (ptype == XML_RELAXNG_EXCEPT) {
06544             if (ret == XML_RELAXNG_CONTENT_ERROR)
06545                 val = XML_RELAXNG_CONTENT_ERROR;
06546             else
06547                 val = XML_RELAXNG_CONTENT_SIMPLE;
06548         } else {
06549             val = xmlRelaxNGGroupContentType(val, ret);
06550         }
06551 
06552     }
06553     return (val);
06554 }
06555 
06556 /**
06557  * xmlRelaxNGParseGrammar:
06558  * @ctxt:  a Relax-NG parser context
06559  * @nodes:  grammar children nodes
06560  *
06561  * parse a Relax-NG <grammar> node
06562  *
06563  * Returns the internal xmlRelaxNGGrammarPtr built or
06564  *         NULL in case of error
06565  */
06566 static xmlRelaxNGGrammarPtr
06567 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
06568 {
06569     xmlRelaxNGGrammarPtr ret, tmp, old;
06570 
06571 #ifdef DEBUG_GRAMMAR
06572     xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
06573 #endif
06574 
06575     ret = xmlRelaxNGNewGrammar(ctxt);
06576     if (ret == NULL)
06577         return (NULL);
06578 
06579     /*
06580      * Link the new grammar in the tree
06581      */
06582     ret->parent = ctxt->grammar;
06583     if (ctxt->grammar != NULL) {
06584         tmp = ctxt->grammar->children;
06585         if (tmp == NULL) {
06586             ctxt->grammar->children = ret;
06587         } else {
06588             while (tmp->next != NULL)
06589                 tmp = tmp->next;
06590             tmp->next = ret;
06591         }
06592     }
06593 
06594     old = ctxt->grammar;
06595     ctxt->grammar = ret;
06596     xmlRelaxNGParseGrammarContent(ctxt, nodes);
06597     ctxt->grammar = ret;
06598     if (ctxt->grammar == NULL) {
06599         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_CONTENT,
06600                    "Failed to parse <grammar> content\n", NULL, NULL);
06601     } else if (ctxt->grammar->start == NULL) {
06602         xmlRngPErr(ctxt, nodes, XML_RNGP_GRAMMAR_NO_START,
06603                    "Element <grammar> has no <start>\n", NULL, NULL);
06604     }
06605 
06606     /*
06607      * Apply 4.17 merging rules to defines and starts
06608      */
06609     xmlRelaxNGCombineStart(ctxt, ret);
06610     if (ret->defs != NULL) {
06611         xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
06612                     ctxt);
06613     }
06614 
06615     /*
06616      * link together defines and refs in this grammar
06617      */
06618     if (ret->refs != NULL) {
06619         xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
06620                     ctxt);
06621     }
06622 
06623 
06624     /* @@@@ */
06625 
06626     ctxt->grammar = old;
06627     return (ret);
06628 }
06629 
06630 /**
06631  * xmlRelaxNGParseDocument:
06632  * @ctxt:  a Relax-NG parser context
06633  * @node:  the root node of the RelaxNG schema
06634  *
06635  * parse a Relax-NG definition resource and build an internal
06636  * xmlRelaxNG struture which can be used to validate instances.
06637  *
06638  * Returns the internal XML RelaxNG structure built or
06639  *         NULL in case of error
06640  */
06641 static xmlRelaxNGPtr
06642 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
06643 {
06644     xmlRelaxNGPtr schema = NULL;
06645     const xmlChar *olddefine;
06646     xmlRelaxNGGrammarPtr old;
06647 
06648     if ((ctxt == NULL) || (node == NULL))
06649         return (NULL);
06650 
06651     schema = xmlRelaxNGNewRelaxNG(ctxt);
06652     if (schema == NULL)
06653         return (NULL);
06654 
06655     olddefine = ctxt->define;
06656     ctxt->define = NULL;
06657     if (IS_RELAXNG(node, "grammar")) {
06658         schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
06659         if (schema->topgrammar == NULL) {
06660             xmlRelaxNGFree(schema);
06661             return (NULL);
06662         }
06663     } else {
06664         xmlRelaxNGGrammarPtr tmp, ret;
06665 
06666         schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
06667         if (schema->topgrammar == NULL) {
06668             xmlRelaxNGFree(schema);
06669             return (NULL);
06670         }
06671         /*
06672          * Link the new grammar in the tree
06673          */
06674         ret->parent = ctxt->grammar;
06675         if (ctxt->grammar != NULL) {
06676             tmp = ctxt->grammar->children;
06677             if (tmp == NULL) {
06678                 ctxt->grammar->children = ret;
06679             } else {
06680                 while (tmp->next != NULL)
06681                     tmp = tmp->next;
06682                 tmp->next = ret;
06683             }
06684         }
06685         old = ctxt->grammar;
06686         ctxt->grammar = ret;
06687         xmlRelaxNGParseStart(ctxt, node);
06688         if (old != NULL)
06689             ctxt->grammar = old;
06690     }
06691     ctxt->define = olddefine;
06692     if (schema->topgrammar->start != NULL) {
06693         xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
06694         if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
06695             xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
06696             while ((schema->topgrammar->start != NULL) &&
06697                    (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
06698                    (schema->topgrammar->start->next != NULL))
06699                 schema->topgrammar->start =
06700                     schema->topgrammar->start->content;
06701             xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
06702                                  XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
06703         }
06704     }
06705 #ifdef DEBUG
06706     if (schema == NULL)
06707         xmlGenericError(xmlGenericErrorContext,
06708                         "xmlRelaxNGParseDocument() failed\n");
06709 #endif
06710 
06711     return (schema);
06712 }
06713 
06714 /************************************************************************
06715  *                                  *
06716  *          Reading RelaxNGs                *
06717  *                                  *
06718  ************************************************************************/
06719 
06720 /**
06721  * xmlRelaxNGNewParserCtxt:
06722  * @URL:  the location of the schema
06723  *
06724  * Create an XML RelaxNGs parse context for that file/resource expected
06725  * to contain an XML RelaxNGs file.
06726  *
06727  * Returns the parser context or NULL in case of error
06728  */
06729 xmlRelaxNGParserCtxtPtr
06730 xmlRelaxNGNewParserCtxt(const char *URL)
06731 {
06732     xmlRelaxNGParserCtxtPtr ret;
06733 
06734     if (URL == NULL)
06735         return (NULL);
06736 
06737     ret =
06738         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
06739     if (ret == NULL) {
06740         xmlRngPErrMemory(NULL, "building parser\n");
06741         return (NULL);
06742     }
06743     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
06744     ret->URL = xmlStrdup((const xmlChar *) URL);
06745     ret->error = xmlGenericError;
06746     ret->userData = xmlGenericErrorContext;
06747     return (ret);
06748 }
06749 
06750 /**
06751  * xmlRelaxNGNewMemParserCtxt:
06752  * @buffer:  a pointer to a char array containing the schemas
06753  * @size:  the size of the array
06754  *
06755  * Create an XML RelaxNGs parse context for that memory buffer expected
06756  * to contain an XML RelaxNGs file.
06757  *
06758  * Returns the parser context or NULL in case of error
06759  */
06760 xmlRelaxNGParserCtxtPtr
06761 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size)
06762 {
06763     xmlRelaxNGParserCtxtPtr ret;
06764 
06765     if ((buffer == NULL) || (size <= 0))
06766         return (NULL);
06767 
06768     ret =
06769         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
06770     if (ret == NULL) {
06771         xmlRngPErrMemory(NULL, "building parser\n");
06772         return (NULL);
06773     }
06774     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
06775     ret->buffer = buffer;
06776     ret->size = size;
06777     ret->error = xmlGenericError;
06778     ret->userData = xmlGenericErrorContext;
06779     return (ret);
06780 }
06781 
06782 /**
06783  * xmlRelaxNGNewDocParserCtxt:
06784  * @doc:  a preparsed document tree
06785  *
06786  * Create an XML RelaxNGs parser context for that document.
06787  * Note: since the process of compiling a RelaxNG schemas modifies the
06788  *       document, the @doc parameter is duplicated internally.
06789  *
06790  * Returns the parser context or NULL in case of error
06791  */
06792 xmlRelaxNGParserCtxtPtr
06793 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc)
06794 {
06795     xmlRelaxNGParserCtxtPtr ret;
06796     xmlDocPtr copy;
06797 
06798     if (doc == NULL)
06799         return (NULL);
06800     copy = xmlCopyDoc(doc, 1);
06801     if (copy == NULL)
06802         return (NULL);
06803 
06804     ret =
06805         (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
06806     if (ret == NULL) {
06807         xmlRngPErrMemory(NULL, "building parser\n");
06808         return (NULL);
06809     }
06810     memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
06811     ret->document = copy;
06812     ret->freedoc = 1;
06813     ret->userData = xmlGenericErrorContext;
06814     return (ret);
06815 }
06816 
06817 /**
06818  * xmlRelaxNGFreeParserCtxt:
06819  * @ctxt:  the schema parser context
06820  *
06821  * Free the resources associated to the schema parser context
06822  */
06823 void
06824 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt)
06825 {
06826     if (ctxt == NULL)
06827         return;
06828     if (ctxt->URL != NULL)
06829         xmlFree(ctxt->URL);
06830     if (ctxt->doc != NULL)
06831         xmlRelaxNGFreeDocument(ctxt->doc);
06832     if (ctxt->interleaves != NULL)
06833         xmlHashFree(ctxt->interleaves, NULL);
06834     if (ctxt->documents != NULL)
06835         xmlRelaxNGFreeDocumentList(ctxt->documents);
06836     if (ctxt->includes != NULL)
06837         xmlRelaxNGFreeIncludeList(ctxt->includes);
06838     if (ctxt->docTab != NULL)
06839         xmlFree(ctxt->docTab);
06840     if (ctxt->incTab != NULL)
06841         xmlFree(ctxt->incTab);
06842     if (ctxt->defTab != NULL) {
06843         int i;
06844 
06845         for (i = 0; i < ctxt->defNr; i++)
06846             xmlRelaxNGFreeDefine(ctxt->defTab[i]);
06847         xmlFree(ctxt->defTab);
06848     }
06849     if ((ctxt->document != NULL) && (ctxt->freedoc))
06850         xmlFreeDoc(ctxt->document);
06851     xmlFree(ctxt);
06852 }
06853 
06854 /**
06855  * xmlRelaxNGNormExtSpace:
06856  * @value:  a value
06857  *
06858  * Removes the leading and ending spaces of the value
06859  * The string is modified "in situ"
06860  */
06861 static void
06862 xmlRelaxNGNormExtSpace(xmlChar * value)
06863 {
06864     xmlChar *start = value;
06865     xmlChar *cur = value;
06866 
06867     if (value == NULL)
06868         return;
06869 
06870     while (IS_BLANK_CH(*cur))
06871         cur++;
06872     if (cur == start) {
06873         do {
06874             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
06875                 cur++;
06876             if (*cur == 0)
06877                 return;
06878             start = cur;
06879             while (IS_BLANK_CH(*cur))
06880                 cur++;
06881             if (*cur == 0) {
06882                 *start = 0;
06883                 return;
06884             }
06885         } while (1);
06886     } else {
06887         do {
06888             while ((*cur != 0) && (!IS_BLANK_CH(*cur)))
06889                 *start++ = *cur++;
06890             if (*cur == 0) {
06891                 *start = 0;
06892                 return;
06893             }
06894             /* don't try to normalize the inner spaces */
06895             while (IS_BLANK_CH(*cur))
06896                 cur++;
06897             if (*cur == 0) {
06898                 *start = 0;
06899                 return;
06900             }
06901             *start++ = *cur++;
06902         } while (1);
06903     }
06904 }
06905 
06906 /**
06907  * xmlRelaxNGCleanupAttributes:
06908  * @ctxt:  a Relax-NG parser context
06909  * @node:  a Relax-NG node
06910  *
06911  * Check all the attributes on the given node
06912  */
06913 static void
06914 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
06915 {
06916     xmlAttrPtr cur, next;
06917 
06918     cur = node->properties;
06919     while (cur != NULL) {
06920         next = cur->next;
06921         if ((cur->ns == NULL) ||
06922             (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
06923             if (xmlStrEqual(cur->name, BAD_CAST "name")) {
06924                 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
06925                     (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
06926                     (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
06927                     (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
06928                     (!xmlStrEqual(node->name, BAD_CAST "param")) &&
06929                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
06930                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
06931                                "Attribute %s is not allowed on %s\n",
06932                                cur->name, node->name);
06933                 }
06934             } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
06935                 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
06936                     (!xmlStrEqual(node->name, BAD_CAST "data"))) {
06937                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
06938                                "Attribute %s is not allowed on %s\n",
06939                                cur->name, node->name);
06940                 }
06941             } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
06942                 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
06943                     (!xmlStrEqual(node->name, BAD_CAST "include"))) {
06944                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
06945                                "Attribute %s is not allowed on %s\n",
06946                                cur->name, node->name);
06947                 }
06948             } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
06949                 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
06950                     (!xmlStrEqual(node->name, BAD_CAST "define"))) {
06951                     xmlRngPErr(ctxt, node, XML_RNGP_FORBIDDEN_ATTRIBUTE,
06952                                "Attribute %s is not allowed on %s\n",
06953                                cur->name, node->name);
06954                 }
06955             } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
06956                 xmlChar *val;
06957                 xmlURIPtr uri;
06958 
06959                 val = xmlNodeListGetString(node->doc, cur->children, 1);
06960                 if (val != NULL) {
06961                     if (val[0] != 0) {
06962                         uri = xmlParseURI((const char *) val);
06963                         if (uri == NULL) {
06964                             xmlRngPErr(ctxt, node, XML_RNGP_INVALID_URI,
06965                                        "Attribute %s contains invalid URI %s\n",
06966                                        cur->name, val);
06967                         } else {
06968                             if (uri->scheme == NULL) {
06969                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_NOT_ABSOLUTE,
06970                                            "Attribute %s URI %s is not absolute\n",
06971                                            cur->name, val);
06972                             }
06973                             if (uri->fragment != NULL) {
06974                                 xmlRngPErr(ctxt, node, XML_RNGP_URI_FRAGMENT,
06975                                            "Attribute %s URI %s has a fragment ID\n",
06976                                            cur->name, val);
06977                             }
06978                             xmlFreeURI(uri);
06979                         }
06980                     }
06981                     xmlFree(val);
06982                 }
06983             } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
06984                 xmlRngPErr(ctxt, node, XML_RNGP_UNKNOWN_ATTRIBUTE,
06985                            "Unknown attribute %s on %s\n", cur->name,
06986                            node->name);
06987             }
06988         }
06989         cur = next;
06990     }
06991 }
06992 
06993 /**
06994  * xmlRelaxNGCleanupTree:
06995  * @ctxt:  a Relax-NG parser context
06996  * @root:  an xmlNodePtr subtree
06997  *
06998  * Cleanup the subtree from unwanted nodes for parsing, resolve
06999  * Include and externalRef lookups.
07000  */
07001 static void
07002 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root)
07003 {
07004     xmlNodePtr cur, delete;
07005 
07006     delete = NULL;
07007     cur = root;
07008     while (cur != NULL) {
07009         if (delete != NULL) {
07010             xmlUnlinkNode(delete);
07011             xmlFreeNode(delete);
07012             delete = NULL;
07013         }
07014         if (cur->type == XML_ELEMENT_NODE) {
07015             /*
07016              * Simplification 4.1. Annotations
07017              */
07018             if ((cur->ns == NULL) ||
07019                 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
07020                 if ((cur->parent != NULL) &&
07021                     (cur->parent->type == XML_ELEMENT_NODE) &&
07022                     ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
07023                      (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
07024                      (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
07025                     xmlRngPErr(ctxt, cur, XML_RNGP_FOREIGN_ELEMENT,
07026                                "element %s doesn't allow foreign elements\n",
07027                                cur->parent->name, NULL);
07028                 }
07029                 delete = cur;
07030                 goto skip_children;
07031             } else {
07032                 xmlRelaxNGCleanupAttributes(ctxt, cur);
07033                 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
07034                     xmlChar *href, *ns, *base, *URL;
07035                     xmlRelaxNGDocumentPtr docu;
07036                     xmlNodePtr tmp;
07037             xmlURIPtr uri;
07038 
07039                     ns = xmlGetProp(cur, BAD_CAST "ns");
07040                     if (ns == NULL) {
07041                         tmp = cur->parent;
07042                         while ((tmp != NULL) &&
07043                                (tmp->type == XML_ELEMENT_NODE)) {
07044                             ns = xmlGetProp(tmp, BAD_CAST "ns");
07045                             if (ns != NULL)
07046                                 break;
07047                             tmp = tmp->parent;
07048                         }
07049                     }
07050                     href = xmlGetProp(cur, BAD_CAST "href");
07051                     if (href == NULL) {
07052                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
07053                                    "xmlRelaxNGParse: externalRef has no href attribute\n",
07054                                    NULL, NULL);
07055                         if (ns != NULL)
07056                             xmlFree(ns);
07057                         delete = cur;
07058                         goto skip_children;
07059                     }
07060             uri = xmlParseURI((const char *) href);
07061             if (uri == NULL) {
07062                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
07063                                    "Incorrect URI for externalRef %s\n",
07064                                    href, NULL);
07065                         if (ns != NULL)
07066                             xmlFree(ns);
07067                         if (href != NULL)
07068                             xmlFree(href);
07069                         delete = cur;
07070                         goto skip_children;
07071             }
07072             if (uri->fragment != NULL) {
07073                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
07074                    "Fragment forbidden in URI for externalRef %s\n",
07075                                    href, NULL);
07076                         if (ns != NULL)
07077                             xmlFree(ns);
07078                 xmlFreeURI(uri);
07079                         if (href != NULL)
07080                             xmlFree(href);
07081                         delete = cur;
07082                         goto skip_children;
07083             }
07084             xmlFreeURI(uri);
07085                     base = xmlNodeGetBase(cur->doc, cur);
07086                     URL = xmlBuildURI(href, base);
07087                     if (URL == NULL) {
07088                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
07089                                    "Failed to compute URL for externalRef %s\n",
07090                                    href, NULL);
07091                         if (ns != NULL)
07092                             xmlFree(ns);
07093                         if (href != NULL)
07094                             xmlFree(href);
07095                         if (base != NULL)
07096                             xmlFree(base);
07097                         delete = cur;
07098                         goto skip_children;
07099                     }
07100                     if (href != NULL)
07101                         xmlFree(href);
07102                     if (base != NULL)
07103                         xmlFree(base);
07104                     docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
07105                     if (docu == NULL) {
07106                         xmlRngPErr(ctxt, cur, XML_RNGP_EXTERNAL_REF_FAILURE,
07107                                    "Failed to load externalRef %s\n", URL,
07108                                    NULL);
07109                         if (ns != NULL)
07110                             xmlFree(ns);
07111                         xmlFree(URL);
07112                         delete = cur;
07113                         goto skip_children;
07114                     }
07115                     if (ns != NULL)
07116                         xmlFree(ns);
07117                     xmlFree(URL);
07118                     cur->psvi = docu;
07119                 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
07120                     xmlChar *href, *ns, *base, *URL;
07121                     xmlRelaxNGIncludePtr incl;
07122                     xmlNodePtr tmp;
07123 
07124                     href = xmlGetProp(cur, BAD_CAST "href");
07125                     if (href == NULL) {
07126                         xmlRngPErr(ctxt, cur, XML_RNGP_MISSING_HREF,
07127                                    "xmlRelaxNGParse: include has no href attribute\n",
07128                                    NULL, NULL);
07129                         delete = cur;
07130                         goto skip_children;
07131                     }
07132                     base = xmlNodeGetBase(cur->doc, cur);
07133                     URL = xmlBuildURI(href, base);
07134                     if (URL == NULL) {
07135                         xmlRngPErr(ctxt, cur, XML_RNGP_HREF_ERROR,
07136                                    "Failed to compute URL for include %s\n",
07137                                    href, NULL);
07138                         if (href != NULL)
07139                             xmlFree(href);
07140                         if (base != NULL)
07141                             xmlFree(base);
07142                         delete = cur;
07143                         goto skip_children;
07144                     }
07145                     if (href != NULL)
07146                         xmlFree(href);
07147                     if (base != NULL)
07148                         xmlFree(base);
07149                     ns = xmlGetProp(cur, BAD_CAST "ns");
07150                     if (ns == NULL) {
07151                         tmp = cur->parent;
07152                         while ((tmp != NULL) &&
07153                                (tmp->type == XML_ELEMENT_NODE)) {
07154                             ns = xmlGetProp(tmp, BAD_CAST "ns");
07155                             if (ns != NULL)
07156                                 break;
07157                             tmp = tmp->parent;
07158                         }
07159                     }
07160                     incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
07161                     if (ns != NULL)
07162                         xmlFree(ns);
07163                     if (incl == NULL) {
07164                         xmlRngPErr(ctxt, cur, XML_RNGP_INCLUDE_FAILURE,
07165                                    "Failed to load include %s\n", URL,
07166                                    NULL);
07167                         xmlFree(URL);
07168                         delete = cur;
07169                         goto skip_children;
07170                     }
07171                     xmlFree(URL);
07172                     cur->psvi = incl;
07173                 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
07174                            (xmlStrEqual(cur->name, BAD_CAST "attribute")))
07175                 {
07176                     xmlChar *name, *ns;
07177                     xmlNodePtr text = NULL;
07178 
07179                     /*
07180                      * Simplification 4.8. name attribute of element
07181                      * and attribute elements
07182                      */
07183                     name = xmlGetProp(cur, BAD_CAST "name");
07184                     if (name != NULL) {
07185                         if (cur->children == NULL) {
07186                             text =
07187                                 xmlNewChild(cur, cur->ns, BAD_CAST "name",
07188                                             name);
07189                         } else {
07190                             xmlNodePtr node;
07191 
07192                             node = xmlNewDocNode(cur->doc, cur->ns,
07193                                      BAD_CAST "name", NULL);
07194                             if (node != NULL) {
07195                                 xmlAddPrevSibling(cur->children, node);
07196                                 text = xmlNewText(name);
07197                                 xmlAddChild(node, text);
07198                                 text = node;
07199                             }
07200                         }
07201                         if (text == NULL) {
07202                             xmlRngPErr(ctxt, cur, XML_RNGP_CREATE_FAILURE,
07203                                        "Failed to create a name %s element\n",
07204                                        name, NULL);
07205                         }
07206                         xmlUnsetProp(cur, BAD_CAST "name");
07207                         xmlFree(name);
07208                         ns = xmlGetProp(cur, BAD_CAST "ns");
07209                         if (ns != NULL) {
07210                             if (text != NULL) {
07211                                 xmlSetProp(text, BAD_CAST "ns", ns);
07212                                 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
07213                             }
07214                             xmlFree(ns);
07215                         } else if (xmlStrEqual(cur->name,
07216                                                BAD_CAST "attribute")) {
07217                             xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
07218                         }
07219                     }
07220                 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
07221                            (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
07222                            (xmlStrEqual(cur->name, BAD_CAST "value"))) {
07223                     /*
07224                      * Simplification 4.8. name attribute of element
07225                      * and attribute elements
07226                      */
07227                     if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
07228                         xmlNodePtr node;
07229                         xmlChar *ns = NULL;
07230 
07231                         node = cur->parent;
07232                         while ((node != NULL) &&
07233                                (node->type == XML_ELEMENT_NODE)) {
07234                             ns = xmlGetProp(node, BAD_CAST "ns");
07235                             if (ns != NULL) {
07236                                 break;
07237                             }
07238                             node = node->parent;
07239                         }
07240                         if (ns == NULL) {
07241                             xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
07242                         } else {
07243                             xmlSetProp(cur, BAD_CAST "ns", ns);
07244                             xmlFree(ns);
07245                         }
07246                     }
07247                     if (xmlStrEqual(cur->name, BAD_CAST "name")) {
07248                         xmlChar *name, *local, *prefix;
07249 
07250                         /*
07251                          * Simplification: 4.10. QNames
07252                          */
07253                         name = xmlNodeGetContent(cur);
07254                         if (name != NULL) {
07255                             local = xmlSplitQName2(name, &prefix);
07256                             if (local != NULL) {
07257                                 xmlNsPtr ns;
07258 
07259                                 ns = xmlSearchNs(cur->doc, cur, prefix);
07260                                 if (ns == NULL) {
07261                                     xmlRngPErr(ctxt, cur,
07262                                                XML_RNGP_PREFIX_UNDEFINED,
07263                                                "xmlRelaxNGParse: no namespace for prefix %s\n",
07264                                                prefix, NULL);
07265                                 } else {
07266                                     xmlSetProp(cur, BAD_CAST "ns",
07267                                                ns->href);
07268                                     xmlNodeSetContent(cur, local);
07269                                 }
07270                                 xmlFree(local);
07271                                 xmlFree(prefix);
07272                             }
07273                             xmlFree(name);
07274                         }
07275                     }
07276                     /*
07277                      * 4.16
07278                      */
07279                     if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
07280                         if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
07281                             xmlRngPErr(ctxt, cur,
07282                                        XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME,
07283                                        "Found nsName/except//nsName forbidden construct\n",
07284                                        NULL, NULL);
07285                         }
07286                     }
07287                 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
07288                            (cur != root)) {
07289                     int oldflags = ctxt->flags;
07290 
07291                     /*
07292                      * 4.16
07293                      */
07294                     if ((cur->parent != NULL) &&
07295                         (xmlStrEqual
07296                          (cur->parent->name, BAD_CAST "anyName"))) {
07297                         ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
07298                         xmlRelaxNGCleanupTree(ctxt, cur);
07299                         ctxt->flags = oldflags;
07300                         goto skip_children;
07301                     } else if ((cur->parent != NULL) &&
07302                                (xmlStrEqual
07303                                 (cur->parent->name, BAD_CAST "nsName"))) {
07304                         ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
07305                         xmlRelaxNGCleanupTree(ctxt, cur);
07306                         ctxt->flags = oldflags;
07307                         goto skip_children;
07308                     }
07309                 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
07310                     /*
07311                      * 4.16
07312                      */
07313                     if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
07314                         xmlRngPErr(ctxt, cur,
07315                                    XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME,
07316                                    "Found anyName/except//anyName forbidden construct\n",
07317                                    NULL, NULL);
07318                     } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
07319                         xmlRngPErr(ctxt, cur,
07320                                    XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME,
07321                                    "Found nsName/except//anyName forbidden construct\n",
07322                                    NULL, NULL);
07323                     }
07324                 }
07325                 /*
07326                  * This is not an else since "include" is transformed
07327                  * into a div
07328                  */
07329                 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
07330                     xmlChar *ns;
07331                     xmlNodePtr child, ins, tmp;
07332 
07333                     /*
07334                      * implements rule 4.11
07335                      */
07336 
07337                     ns = xmlGetProp(cur, BAD_CAST "ns");
07338 
07339                     child = cur->children;
07340                     ins = cur;
07341                     while (child != NULL) {
07342                         if (ns != NULL) {
07343                             if (!xmlHasProp(child, BAD_CAST "ns")) {
07344                                 xmlSetProp(child, BAD_CAST "ns", ns);
07345                             }
07346                         }
07347                         tmp = child->next;
07348                         xmlUnlinkNode(child);
07349                         ins = xmlAddNextSibling(ins, child);
07350                         child = tmp;
07351                     }
07352                     if (ns != NULL)
07353                         xmlFree(ns);
07354             /*
07355              * Since we are about to delete cur, if its nsDef is non-NULL we
07356              * need to preserve it (it contains the ns definitions for the
07357              * children we just moved).  We'll just stick it on to the end
07358              * of cur->parent's list, since it's never going to be re-serialized
07359              * (bug 143738).
07360              */
07361             if ((cur->nsDef != NULL) && (cur->parent != NULL)) {
07362             xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
07363             while (parDef->next != NULL)
07364                 parDef = parDef->next;
07365             parDef->next = cur->nsDef;
07366             cur->nsDef = NULL;
07367             }
07368                     delete = cur;
07369                     goto skip_children;
07370                 }
07371             }
07372         }
07373         /*
07374          * Simplification 4.2 whitespaces
07375          */
07376         else if ((cur->type == XML_TEXT_NODE) ||
07377                  (cur->type == XML_CDATA_SECTION_NODE)) {
07378             if (IS_BLANK_NODE(cur)) {
07379                 if ((cur->parent != NULL) &&
07380             (cur->parent->type == XML_ELEMENT_NODE)) {
07381                     if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
07382                         &&
07383                         (!xmlStrEqual
07384                          (cur->parent->name, BAD_CAST "param")))
07385                         delete = cur;
07386                 } else {
07387                     delete = cur;
07388                     goto skip_children;
07389                 }
07390             }
07391         } else {
07392             delete = cur;
07393             goto skip_children;
07394         }
07395 
07396         /*
07397          * Skip to next node
07398          */
07399         if (cur->children != NULL) {
07400             if ((cur->children->type != XML_ENTITY_DECL) &&
07401                 (cur->children->type != XML_ENTITY_REF_NODE) &&
07402                 (cur->children->type != XML_ENTITY_NODE)) {
07403                 cur = cur->children;
07404                 continue;
07405             }
07406         }
07407       skip_children:
07408         if (cur->next != NULL) {
07409             cur = cur->next;
07410             continue;
07411         }
07412 
07413         do {
07414             cur = cur->parent;
07415             if (cur == NULL)
07416                 break;
07417             if (cur == root) {
07418                 cur = NULL;
07419                 break;
07420             }
07421             if (cur->next != NULL) {
07422                 cur = cur->next;
07423                 break;
07424             }
07425         } while (cur != NULL);
07426     }
07427     if (delete != NULL) {
07428         xmlUnlinkNode(delete);
07429         xmlFreeNode(delete);
07430         delete = NULL;
07431     }
07432 }
07433 
07434 /**
07435  * xmlRelaxNGCleanupDoc:
07436  * @ctxt:  a Relax-NG parser context
07437  * @doc:  an xmldocPtr document pointer
07438  *
07439  * Cleanup the document from unwanted nodes for parsing, resolve
07440  * Include and externalRef lookups.
07441  *
07442  * Returns the cleaned up document or NULL in case of error
07443  */
07444 static xmlDocPtr
07445 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc)
07446 {
07447     xmlNodePtr root;
07448 
07449     /*
07450      * Extract the root
07451      */
07452     root = xmlDocGetRootElement(doc);
07453     if (root == NULL) {
07454         xmlRngPErr(ctxt, (xmlNodePtr) doc, XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
07455                    ctxt->URL, NULL);
07456         return (NULL);
07457     }
07458     xmlRelaxNGCleanupTree(ctxt, root);
07459     return (doc);
07460 }
07461 
07462 /**
07463  * xmlRelaxNGParse:
07464  * @ctxt:  a Relax-NG parser context
07465  *
07466  * parse a schema definition resource and build an internal
07467  * XML Shema struture which can be used to validate instances.
07468  *
07469  * Returns the internal XML RelaxNG structure built from the resource or
07470  *         NULL in case of error
07471  */
07472 xmlRelaxNGPtr
07473 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
07474 {
07475     xmlRelaxNGPtr ret = NULL;
07476     xmlDocPtr doc;
07477     xmlNodePtr root;
07478 
07479     xmlRelaxNGInitTypes();
07480 
07481     if (ctxt == NULL)
07482         return (NULL);
07483 
07484     /*
07485      * First step is to parse the input document into an DOM/Infoset
07486      */
07487     if (ctxt->URL != NULL) {
07488         doc = xmlReadFile((const char *) ctxt->URL,NULL,0);
07489         if (doc == NULL) {
07490             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
07491                        "xmlRelaxNGParse: could not load %s\n", ctxt->URL,
07492                        NULL);
07493             return (NULL);
07494         }
07495     } else if (ctxt->buffer != NULL) {
07496         doc = xmlReadMemory(ctxt->buffer, ctxt->size,NULL,NULL,0);
07497         if (doc == NULL) {
07498             xmlRngPErr(ctxt, NULL, XML_RNGP_PARSE_ERROR,
07499                        "xmlRelaxNGParse: could not parse schemas\n", NULL,
07500                        NULL);
07501             return (NULL);
07502         }
07503         doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
07504         ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
07505     } else if (ctxt->document != NULL) {
07506         doc = ctxt->document;
07507     } else {
07508         xmlRngPErr(ctxt, NULL, XML_RNGP_EMPTY,
07509                    "xmlRelaxNGParse: nothing to parse\n", NULL, NULL);
07510         return (NULL);
07511     }
07512     ctxt->document = doc;
07513 
07514     /*
07515      * Some preprocessing of the document content
07516      */
07517     doc = xmlRelaxNGCleanupDoc(ctxt, doc);
07518     if (doc == NULL) {
07519         xmlFreeDoc(ctxt->document);
07520         ctxt->document = NULL;
07521         return (NULL);
07522     }
07523 
07524     /*
07525      * Then do the parsing for good
07526      */
07527     root = xmlDocGetRootElement(doc);
07528     if (root == NULL) {
07529         xmlRngPErr(ctxt, (xmlNodePtr) doc,
07530                XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
07531                    (ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
07532 
07533         xmlFreeDoc(ctxt->document);
07534         ctxt->document = NULL;
07535         return (NULL);
07536     }
07537     ret = xmlRelaxNGParseDocument(ctxt, root);
07538     if (ret == NULL) {
07539         xmlFreeDoc(ctxt->document);
07540         ctxt->document = NULL;
07541         return (NULL);
07542     }
07543 
07544     /*
07545      * Check the ref/defines links
07546      */
07547     /*
07548      * try to preprocess interleaves
07549      */
07550     if (ctxt->interleaves != NULL) {
07551         xmlHashScan(ctxt->interleaves,
07552                     (xmlHashScanner) xmlRelaxNGComputeInterleaves, ctxt);
07553     }
07554 
07555     /*
07556      * if there was a parsing error return NULL
07557      */
07558     if (ctxt->nbErrors > 0) {
07559         xmlRelaxNGFree(ret);
07560         ctxt->document = NULL;
07561         xmlFreeDoc(doc);
07562         return (NULL);
07563     }
07564 
07565     /*
07566      * try to compile (parts of) the schemas
07567      */
07568     if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
07569         if (ret->topgrammar->start->type != XML_RELAXNG_START) {
07570             xmlRelaxNGDefinePtr def;
07571 
07572             def = xmlRelaxNGNewDefine(ctxt, NULL);
07573             if (def != NULL) {
07574                 def->type = XML_RELAXNG_START;
07575                 def->content = ret->topgrammar->start;
07576                 ret->topgrammar->start = def;
07577             }
07578         }
07579         xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
07580     }
07581 
07582     /*
07583      * Transfer the pointer for cleanup at the schema level.
07584      */
07585     ret->doc = doc;
07586     ctxt->document = NULL;
07587     ret->documents = ctxt->documents;
07588     ctxt->documents = NULL;
07589 
07590     ret->includes = ctxt->includes;
07591     ctxt->includes = NULL;
07592     ret->defNr = ctxt->defNr;
07593     ret->defTab = ctxt->defTab;
07594     ctxt->defTab = NULL;
07595     if (ctxt->idref == 1)
07596         ret->idref = 1;
07597 
07598     return (ret);
07599 }
07600 
07601 /**
07602  * xmlRelaxNGSetParserErrors:
07603  * @ctxt:  a Relax-NG validation context
07604  * @err:  the error callback
07605  * @warn:  the warning callback
07606  * @ctx:  contextual data for the callbacks
07607  *
07608  * Set the callback functions used to handle errors for a validation context
07609  */
07610 void
07611 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
07612                           xmlRelaxNGValidityErrorFunc err,
07613                           xmlRelaxNGValidityWarningFunc warn, void *ctx)
07614 {
07615     if (ctxt == NULL)
07616         return;
07617     ctxt->error = err;
07618     ctxt->warning = warn;
07619     ctxt->serror = NULL;
07620     ctxt->userData = ctx;
07621 }
07622 
07623 /**
07624  * xmlRelaxNGGetParserErrors:
07625  * @ctxt:  a Relax-NG validation context
07626  * @err:  the error callback result
07627  * @warn:  the warning callback result
07628  * @ctx:  contextual data for the callbacks result
07629  *
07630  * Get the callback information used to handle errors for a validation context
07631  *
07632  * Returns -1 in case of failure, 0 otherwise.
07633  */
07634 int
07635 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
07636                           xmlRelaxNGValidityErrorFunc * err,
07637                           xmlRelaxNGValidityWarningFunc * warn, void **ctx)
07638 {
07639     if (ctxt == NULL)
07640         return (-1);
07641     if (err != NULL)
07642         *err = ctxt->error;
07643     if (warn != NULL)
07644         *warn = ctxt->warning;
07645     if (ctx != NULL)
07646         *ctx = ctxt->userData;
07647     return (0);
07648 }
07649 
07650 /**
07651  * xmlRelaxNGSetParserStructuredErrors:
07652  * @ctxt:  a Relax-NG parser context
07653  * @serror:  the error callback
07654  * @ctx:  contextual data for the callbacks
07655  *
07656  * Set the callback functions used to handle errors for a parsing context
07657  */
07658 void
07659 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt,
07660                     xmlStructuredErrorFunc serror,
07661                     void *ctx)
07662 {
07663     if (ctxt == NULL)
07664         return;
07665     ctxt->serror = serror;
07666     ctxt->error = NULL;
07667     ctxt->warning = NULL;
07668     ctxt->userData = ctx;
07669 }
07670 
07671 #ifdef LIBXML_OUTPUT_ENABLED
07672 
07673 /************************************************************************
07674  *                                  *
07675  *          Dump back a compiled form           *
07676  *                                  *
07677  ************************************************************************/
07678 static void xmlRelaxNGDumpDefine(FILE * output,
07679                                  xmlRelaxNGDefinePtr define);
07680 
07681 /**
07682  * xmlRelaxNGDumpDefines:
07683  * @output:  the file output
07684  * @defines:  a list of define structures
07685  *
07686  * Dump a RelaxNG structure back
07687  */
07688 static void
07689 xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines)
07690 {
07691     while (defines != NULL) {
07692         xmlRelaxNGDumpDefine(output, defines);
07693         defines = defines->next;
07694     }
07695 }
07696 
07697 /**
07698  * xmlRelaxNGDumpDefine:
07699  * @output:  the file output
07700  * @define:  a define structure
07701  *
07702  * Dump a RelaxNG structure back
07703  */
07704 static void
07705 xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define)
07706 {
07707     if (define == NULL)
07708         return;
07709     switch (define->type) {
07710         case XML_RELAXNG_EMPTY:
07711             fprintf(output, "<empty/>\n");
07712             break;
07713         case XML_RELAXNG_NOT_ALLOWED:
07714             fprintf(output, "<notAllowed/>\n");
07715             break;
07716         case XML_RELAXNG_TEXT:
07717             fprintf(output, "<text/>\n");
07718             break;
07719         case XML_RELAXNG_ELEMENT:
07720             fprintf(output, "<element>\n");
07721             if (define->name != NULL) {
07722                 fprintf(output, "<name");
07723                 if (define->ns != NULL)
07724                     fprintf(output, " ns=\"%s\"", define->ns);
07725                 fprintf(output, ">%s</name>\n", define->name);
07726             }
07727             xmlRelaxNGDumpDefines(output, define->attrs);
07728             xmlRelaxNGDumpDefines(output, define->content);
07729             fprintf(output, "</element>\n");
07730             break;
07731         case XML_RELAXNG_LIST:
07732             fprintf(output, "<list>\n");
07733             xmlRelaxNGDumpDefines(output, define->content);
07734             fprintf(output, "</list>\n");
07735             break;
07736         case XML_RELAXNG_ONEORMORE:
07737             fprintf(output, "<oneOrMore>\n");
07738             xmlRelaxNGDumpDefines(output, define->content);
07739             fprintf(output, "</oneOrMore>\n");
07740             break;
07741         case XML_RELAXNG_ZEROORMORE:
07742             fprintf(output, "<zeroOrMore>\n");
07743             xmlRelaxNGDumpDefines(output, define->content);
07744             fprintf(output, "</zeroOrMore>\n");
07745             break;
07746         case XML_RELAXNG_CHOICE:
07747             fprintf(output, "<choice>\n");
07748             xmlRelaxNGDumpDefines(output, define->content);
07749             fprintf(output, "</choice>\n");
07750             break;
07751         case XML_RELAXNG_GROUP:
07752             fprintf(output, "<group>\n");
07753             xmlRelaxNGDumpDefines(output, define->content);
07754             fprintf(output, "</group>\n");
07755             break;
07756         case XML_RELAXNG_INTERLEAVE:
07757             fprintf(output, "<interleave>\n");
07758             xmlRelaxNGDumpDefines(output, define->content);
07759             fprintf(output, "</interleave>\n");
07760             break;
07761         case XML_RELAXNG_OPTIONAL:
07762             fprintf(output, "<optional>\n");
07763             xmlRelaxNGDumpDefines(output, define->content);
07764             fprintf(output, "</optional>\n");
07765             break;
07766         case XML_RELAXNG_ATTRIBUTE:
07767             fprintf(output, "<attribute>\n");
07768             xmlRelaxNGDumpDefines(output, define->content);
07769             fprintf(output, "</attribute>\n");
07770             break;
07771         case XML_RELAXNG_DEF:
07772             fprintf(output, "<define");
07773             if (define->name != NULL)
07774                 fprintf(output, " name=\"%s\"", define->name);
07775             fprintf(output, ">\n");
07776             xmlRelaxNGDumpDefines(output, define->content);
07777             fprintf(output, "</define>\n");
07778             break;
07779         case XML_RELAXNG_REF:
07780             fprintf(output, "<ref");
07781             if (define->name != NULL)
07782                 fprintf(output, " name=\"%s\"", define->name);
07783             fprintf(output, ">\n");
07784             xmlRelaxNGDumpDefines(output, define->content);
07785             fprintf(output, "</ref>\n");
07786             break;
07787         case XML_RELAXNG_PARENTREF:
07788             fprintf(output, "<parentRef");
07789             if (define->name != NULL)
07790                 fprintf(output, " name=\"%s\"", define->name);
07791             fprintf(output, ">\n");
07792             xmlRelaxNGDumpDefines(output, define->content);
07793             fprintf(output, "</parentRef>\n");
07794             break;
07795         case XML_RELAXNG_EXTERNALREF:
07796             fprintf(output, "<externalRef>");
07797             xmlRelaxNGDumpDefines(output, define->content);
07798             fprintf(output, "</externalRef>\n");
07799             break;
07800         case XML_RELAXNG_DATATYPE:
07801         case XML_RELAXNG_VALUE:
07802             TODO break;
07803         case XML_RELAXNG_START:
07804         case XML_RELAXNG_EXCEPT:
07805         case XML_RELAXNG_PARAM:
07806             TODO break;
07807         case XML_RELAXNG_NOOP:
07808             xmlRelaxNGDumpDefines(output, define->content);
07809             break;
07810     }
07811 }
07812 
07813 /**
07814  * xmlRelaxNGDumpGrammar:
07815  * @output:  the file output
07816  * @grammar:  a grammar structure
07817  * @top:  is this a top grammar
07818  *
07819  * Dump a RelaxNG structure back
07820  */
07821 static void
07822 xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
07823 {
07824     if (grammar == NULL)
07825         return;
07826 
07827     fprintf(output, "<grammar");
07828     if (top)
07829         fprintf(output, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
07830     switch (grammar->combine) {
07831         case XML_RELAXNG_COMBINE_UNDEFINED:
07832             break;
07833         case XML_RELAXNG_COMBINE_CHOICE:
07834             fprintf(output, " combine=\"choice\"");
07835             break;
07836         case XML_RELAXNG_COMBINE_INTERLEAVE:
07837             fprintf(output, " combine=\"interleave\"");
07838             break;
07839         default:
07840             fprintf(output, " <!-- invalid combine value -->");
07841     }
07842     fprintf(output, ">\n");
07843     if (grammar->start == NULL) {
07844         fprintf(output, " <!-- grammar had no start -->");
07845     } else {
07846         fprintf(output, "<start>\n");
07847         xmlRelaxNGDumpDefine(output, grammar->start);
07848         fprintf(output, "</start>\n");
07849     }
07850     /* TODO ? Dump the defines ? */
07851     fprintf(output, "</grammar>\n");
07852 }
07853 
07854 /**
07855  * xmlRelaxNGDump:
07856  * @output:  the file output
07857  * @schema:  a schema structure
07858  *
07859  * Dump a RelaxNG structure back
07860  */
07861 void
07862 xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
07863 {
07864     if (output == NULL)
07865         return;
07866     if (schema == NULL) {
07867         fprintf(output, "RelaxNG empty or failed to compile\n");
07868         return;
07869     }
07870     fprintf(output, "RelaxNG: ");
07871     if (schema->doc == NULL) {
07872         fprintf(output, "no document\n");
07873     } else if (schema->doc->URL != NULL) {
07874         fprintf(output, "%s\n", schema->doc->URL);
07875     } else {
07876         fprintf(output, "\n");
07877     }
07878     if (schema->topgrammar == NULL) {
07879         fprintf(output, "RelaxNG has no top grammar\n");
07880         return;
07881     }
07882     xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
07883 }
07884 
07885 /**
07886  * xmlRelaxNGDumpTree:
07887  * @output:  the file output
07888  * @schema:  a schema structure
07889  *
07890  * Dump the transformed RelaxNG tree.
07891  */
07892 void
07893 xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
07894 {
07895     if (output == NULL)
07896         return;
07897     if (schema == NULL) {
07898         fprintf(output, "RelaxNG empty or failed to compile\n");
07899         return;
07900     }
07901     if (schema->doc == NULL) {
07902         fprintf(output, "no document\n");
07903     } else {
07904         xmlDocDump(output, schema->doc);
07905     }
07906 }
07907 #endif /* LIBXML_OUTPUT_ENABLED */
07908 
07909 /************************************************************************
07910  *                                  *
07911  *      Validation of compiled content              *
07912  *                                  *
07913  ************************************************************************/
07914 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
07915                                         xmlRelaxNGDefinePtr define);
07916 
07917 /**
07918  * xmlRelaxNGValidateCompiledCallback:
07919  * @exec:  the regular expression instance
07920  * @token:  the token which matched
07921  * @transdata:  callback data, the define for the subelement if available
07922  @ @inputdata:  callback data, the Relax NG validation context
07923  *
07924  * Handle the callback and if needed validate the element children.
07925  */
07926 static void
07927 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
07928                                    const xmlChar * token,
07929                                    void *transdata, void *inputdata)
07930 {
07931     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
07932     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
07933     int ret;
07934 
07935 #ifdef DEBUG_COMPILE
07936     xmlGenericError(xmlGenericErrorContext,
07937                     "Compiled callback for: '%s'\n", token);
07938 #endif
07939     if (ctxt == NULL) {
07940         fprintf(stderr, "callback on %s missing context\n", token);
07941         return;
07942     }
07943     if (define == NULL) {
07944         if (token[0] == '#')
07945             return;
07946         fprintf(stderr, "callback on %s missing define\n", token);
07947         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
07948             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
07949         return;
07950     }
07951     if ((ctxt == NULL) || (define == NULL)) {
07952         fprintf(stderr, "callback on %s missing info\n", token);
07953         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
07954             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
07955         return;
07956     } else if (define->type != XML_RELAXNG_ELEMENT) {
07957         fprintf(stderr, "callback on %s define is not element\n", token);
07958         if (ctxt->errNo == XML_RELAXNG_OK)
07959             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
07960         return;
07961     }
07962     ret = xmlRelaxNGValidateDefinition(ctxt, define);
07963     if (ret != 0)
07964         ctxt->perr = ret;
07965 }
07966 
07967 /**
07968  * xmlRelaxNGValidateCompiledContent:
07969  * @ctxt:  the RelaxNG validation context
07970  * @regexp:  the regular expression as compiled
07971  * @content:  list of children to test against the regexp
07972  *
07973  * Validate the content model of an element or start using the regexp
07974  *
07975  * Returns 0 in case of success, -1 in case of error.
07976  */
07977 static int
07978 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
07979                                   xmlRegexpPtr regexp, xmlNodePtr content)
07980 {
07981     xmlRegExecCtxtPtr exec;
07982     xmlNodePtr cur;
07983     int ret = 0;
07984     int oldperr;
07985 
07986     if ((ctxt == NULL) || (regexp == NULL))
07987         return (-1);
07988     oldperr = ctxt->perr;
07989     exec = xmlRegNewExecCtxt(regexp,
07990                              xmlRelaxNGValidateCompiledCallback, ctxt);
07991     ctxt->perr = 0;
07992     cur = content;
07993     while (cur != NULL) {
07994         ctxt->state->seq = cur;
07995         switch (cur->type) {
07996             case XML_TEXT_NODE:
07997             case XML_CDATA_SECTION_NODE:
07998                 if (xmlIsBlankNode(cur))
07999                     break;
08000                 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
08001                 if (ret < 0) {
08002                     VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG,
08003                                cur->parent->name);
08004                 }
08005                 break;
08006             case XML_ELEMENT_NODE:
08007                 if (cur->ns != NULL) {
08008                     ret = xmlRegExecPushString2(exec, cur->name,
08009                                                 cur->ns->href, ctxt);
08010                 } else {
08011                     ret = xmlRegExecPushString(exec, cur->name, ctxt);
08012                 }
08013                 if (ret < 0) {
08014                     VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
08015                 }
08016                 break;
08017             default:
08018                 break;
08019         }
08020         if (ret < 0)
08021             break;
08022         /*
08023          * Switch to next element
08024          */
08025         cur = cur->next;
08026     }
08027     ret = xmlRegExecPushString(exec, NULL, NULL);
08028     if (ret == 1) {
08029         ret = 0;
08030         ctxt->state->seq = NULL;
08031     } else if (ret == 0) {
08032         /*
08033          * TODO: get some of the names needed to exit the current state of exec
08034          */
08035         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
08036         ret = -1;
08037         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
08038             xmlRelaxNGDumpValidError(ctxt);
08039     } else {
08040         ret = -1;
08041     }
08042     xmlRegFreeExecCtxt(exec);
08043     /*
08044      * There might be content model errors outside of the pure
08045      * regexp validation, e.g. for attribute values.
08046      */
08047     if ((ret == 0) && (ctxt->perr != 0)) {
08048         ret = ctxt->perr;
08049     }
08050     ctxt->perr = oldperr;
08051     return (ret);
08052 }
08053 
08054 /************************************************************************
08055  *                                  *
08056  *      Progressive validation of when possible         *
08057  *                                  *
08058  ************************************************************************/
08059 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
08060                                            xmlRelaxNGDefinePtr defines);
08061 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt,
08062                                         int dolog);
08063 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt);
08064 
08065 /**
08066  * xmlRelaxNGElemPush:
08067  * @ctxt:  the validation context
08068  * @exec:  the regexp runtime for the new content model
08069  *
08070  * Push a new regexp for the current node content model on the stack
08071  *
08072  * Returns 0 in case of success and -1 in case of error.
08073  */
08074 static int
08075 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec)
08076 {
08077     if (ctxt->elemTab == NULL) {
08078         ctxt->elemMax = 10;
08079         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
08080                                                         sizeof
08081                                                         (xmlRegExecCtxtPtr));
08082         if (ctxt->elemTab == NULL) {
08083             xmlRngVErrMemory(ctxt, "validating\n");
08084             return (-1);
08085         }
08086     }
08087     if (ctxt->elemNr >= ctxt->elemMax) {
08088         ctxt->elemMax *= 2;
08089         ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
08090                                                          ctxt->elemMax *
08091                                                          sizeof
08092                                                          (xmlRegExecCtxtPtr));
08093         if (ctxt->elemTab == NULL) {
08094             xmlRngVErrMemory(ctxt, "validating\n");
08095             return (-1);
08096         }
08097     }
08098     ctxt->elemTab[ctxt->elemNr++] = exec;
08099     ctxt->elem = exec;
08100     return (0);
08101 }
08102 
08103 /**
08104  * xmlRelaxNGElemPop:
08105  * @ctxt:  the validation context
08106  *
08107  * Pop the regexp of the current node content model from the stack
08108  *
08109  * Returns the exec or NULL if empty
08110  */
08111 static xmlRegExecCtxtPtr
08112 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt)
08113 {
08114     xmlRegExecCtxtPtr ret;
08115 
08116     if (ctxt->elemNr <= 0)
08117         return (NULL);
08118     ctxt->elemNr--;
08119     ret = ctxt->elemTab[ctxt->elemNr];
08120     ctxt->elemTab[ctxt->elemNr] = NULL;
08121     if (ctxt->elemNr > 0)
08122         ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
08123     else
08124         ctxt->elem = NULL;
08125     return (ret);
08126 }
08127 
08128 /**
08129  * xmlRelaxNGValidateProgressiveCallback:
08130  * @exec:  the regular expression instance
08131  * @token:  the token which matched
08132  * @transdata:  callback data, the define for the subelement if available
08133  @ @inputdata:  callback data, the Relax NG validation context
08134  *
08135  * Handle the callback and if needed validate the element children.
08136  * some of the in/out informations are passed via the context in @inputdata.
08137  */
08138 static void
08139 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
08140                                       ATTRIBUTE_UNUSED,
08141                                       const xmlChar * token,
08142                                       void *transdata, void *inputdata)
08143 {
08144     xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
08145     xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
08146     xmlRelaxNGValidStatePtr state, oldstate;
08147     xmlNodePtr node;
08148     int ret = 0, oldflags;
08149 
08150 #ifdef DEBUG_PROGRESSIVE
08151     xmlGenericError(xmlGenericErrorContext,
08152                     "Progressive callback for: '%s'\n", token);
08153 #endif
08154     if (ctxt == NULL) {
08155         fprintf(stderr, "callback on %s missing context\n", token);
08156         return;
08157     }
08158     node = ctxt->pnode;
08159     ctxt->pstate = 1;
08160     if (define == NULL) {
08161         if (token[0] == '#')
08162             return;
08163         fprintf(stderr, "callback on %s missing define\n", token);
08164         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
08165             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
08166         ctxt->pstate = -1;
08167         return;
08168     }
08169     if ((ctxt == NULL) || (define == NULL)) {
08170         fprintf(stderr, "callback on %s missing info\n", token);
08171         if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
08172             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
08173         ctxt->pstate = -1;
08174         return;
08175     } else if (define->type != XML_RELAXNG_ELEMENT) {
08176         fprintf(stderr, "callback on %s define is not element\n", token);
08177         if (ctxt->errNo == XML_RELAXNG_OK)
08178             ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
08179         ctxt->pstate = -1;
08180         return;
08181     }
08182     if (node->type != XML_ELEMENT_NODE) {
08183         VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
08184         if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
08185             xmlRelaxNGDumpValidError(ctxt);
08186         ctxt->pstate = -1;
08187         return;
08188     }
08189     if (define->contModel == NULL) {
08190         /*
08191          * this node cannot be validated in a streamable fashion
08192          */
08193 #ifdef DEBUG_PROGRESSIVE
08194         xmlGenericError(xmlGenericErrorContext,
08195                         "Element '%s' validation is not streamable\n",
08196                         token);
08197 #endif
08198         ctxt->pstate = 0;
08199         ctxt->pdef = define;
08200         return;
08201     }
08202     exec = xmlRegNewExecCtxt(define->contModel,
08203                              xmlRelaxNGValidateProgressiveCallback, ctxt);
08204     if (exec == NULL) {
08205         ctxt->pstate = -1;
08206         return;
08207     }
08208     xmlRelaxNGElemPush(ctxt, exec);
08209 
08210     /*
08211      * Validate the attributes part of the content.
08212      */
08213     state = xmlRelaxNGNewValidState(ctxt, node);
08214     if (state == NULL) {
08215         ctxt->pstate = -1;
08216         return;
08217     }
08218     oldstate = ctxt->state;
08219     ctxt->state = state;
08220     if (define->attrs != NULL) {
08221         ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
08222         if (ret != 0) {
08223             ctxt->pstate = -1;
08224             VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
08225         }
08226     }
08227     if (ctxt->state != NULL) {
08228         ctxt->state->seq = NULL;
08229         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
08230         if (ret != 0) {
08231             ctxt->pstate = -1;
08232         }
08233         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
08234     } else if (ctxt->states != NULL) {
08235         int tmp = -1, i;
08236 
08237         oldflags = ctxt->flags;
08238 
08239         for (i = 0; i < ctxt->states->nbState; i++) {
08240             state = ctxt->states->tabState[i];
08241             ctxt->state = state;
08242             ctxt->state->seq = NULL;
08243 
08244             if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
08245                 tmp = 0;
08246                 break;
08247             }
08248         }
08249         if (tmp != 0) {
08250             /*
08251              * validation error, log the message for the "best" one
08252              */
08253             ctxt->flags |= FLAGS_IGNORABLE;
08254             xmlRelaxNGLogBestError(ctxt);
08255         }
08256         for (i = 0; i < ctxt->states->nbState; i++) {
08257             xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[i]);
08258         }
08259         xmlRelaxNGFreeStates(ctxt, ctxt->states);
08260         ctxt->states = NULL;
08261         if ((ret == 0) && (tmp == -1))
08262             ctxt->pstate = -1;
08263         ctxt->flags = oldflags;
08264     }
08265     if (ctxt->pstate == -1) {
08266         if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
08267             xmlRelaxNGDumpValidError(ctxt);
08268         }
08269     }
08270     ctxt->state = oldstate;
08271 }
08272 
08273 /**
08274  * xmlRelaxNGValidatePushElement:
08275  * @ctxt:  the validation context
08276  * @doc:  a document instance
08277  * @elem:  an element instance
08278  *
08279  * Push a new element start on the RelaxNG validation stack.
08280  *
08281  * returns 1 if no validation problem was found or 0 if validating the
08282  *         element requires a full node, and -1 in case of error.
08283  */
08284 int
08285 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
08286                               xmlDocPtr doc ATTRIBUTE_UNUSED,
08287                               xmlNodePtr elem)
08288 {
08289     int ret = 1;
08290 
08291     if ((ctxt == NULL) || (elem == NULL))
08292         return (-1);
08293 
08294 #ifdef DEBUG_PROGRESSIVE
08295     xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
08296 #endif
08297     if (ctxt->elem == 0) {
08298         xmlRelaxNGPtr schema;
08299         xmlRelaxNGGrammarPtr grammar;
08300         xmlRegExecCtxtPtr exec;
08301         xmlRelaxNGDefinePtr define;
08302 
08303         schema = ctxt->schema;
08304         if (schema == NULL) {
08305             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
08306             return (-1);
08307         }
08308         grammar = schema->topgrammar;
08309         if ((grammar == NULL) || (grammar->start == NULL)) {
08310             VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
08311             return (-1);
08312         }
08313         define = grammar->start;
08314         if (define->contModel == NULL) {
08315             ctxt->pdef = define;
08316             return (0);
08317         }
08318         exec = xmlRegNewExecCtxt(define->contModel,
08319                                  xmlRelaxNGValidateProgressiveCallback,
08320                                  ctxt);
08321         if (exec == NULL) {
08322             return (-1);
08323         }
08324         xmlRelaxNGElemPush(ctxt, exec);
08325     }
08326     ctxt->pnode = elem;
08327     ctxt->pstate = 0;
08328     if (elem->ns != NULL) {
08329         ret =
08330             xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
08331                                   ctxt);
08332     } else {
08333         ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
08334     }
08335     if (ret < 0) {
08336         VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
08337     } else {
08338         if (ctxt->pstate == 0)
08339             ret = 0;
08340         else if (ctxt->pstate < 0)
08341             ret = -1;
08342         else
08343             ret = 1;
08344     }
08345 #ifdef DEBUG_PROGRESSIVE
08346     if (ret < 0)
08347         xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
08348                         elem->name);
08349 #endif
08350     return (ret);
08351 }
08352 
08353 /**
08354  * xmlRelaxNGValidatePushCData:
08355  * @ctxt:  the RelaxNG validation context
08356  * @data:  some character data read
08357  * @len:  the length of the data
08358  *
08359  * check the CData parsed for validation in the current stack
08360  *
08361  * returns 1 if no validation problem was found or -1 otherwise
08362  */
08363 int
08364 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
08365                             const xmlChar * data, int len ATTRIBUTE_UNUSED)
08366 {
08367     int ret = 1;
08368 
08369     if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
08370         return (-1);
08371 
08372 #ifdef DEBUG_PROGRESSIVE
08373     xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
08374 #endif
08375 
08376     while (*data != 0) {
08377         if (!IS_BLANK_CH(*data))
08378             break;
08379         data++;
08380     }
08381     if (*data == 0)
08382         return (1);
08383 
08384     ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
08385     if (ret < 0) {
08386         VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
08387 #ifdef DEBUG_PROGRESSIVE
08388         xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
08389 #endif
08390 
08391         return (-1);
08392     }
08393     return (1);
08394 }
08395 
08396 /**
08397  * xmlRelaxNGValidatePopElement:
08398  * @ctxt:  the RelaxNG validation context
08399  * @doc:  a document instance
08400  * @elem:  an element instance
08401  *
08402  * Pop the element end from the RelaxNG validation stack.
08403  *
08404  * returns 1 if no validation problem was found or 0 otherwise
08405  */
08406 int
08407 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
08408                              xmlDocPtr doc ATTRIBUTE_UNUSED,
08409                              xmlNodePtr elem)
08410 {
08411     int ret;
08412     xmlRegExecCtxtPtr exec;
08413 
08414     if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL))
08415         return (-1);
08416 #ifdef DEBUG_PROGRESSIVE
08417     xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
08418 #endif
08419     /*
08420      * verify that we reached a terminal state of the content model.
08421      */
08422     exec = xmlRelaxNGElemPop(ctxt);
08423     ret = xmlRegExecPushString(exec, NULL, NULL);
08424     if (ret == 0) {
08425         /*
08426          * TODO: get some of the names needed to exit the current state of exec
08427          */
08428         VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
08429         ret = -1;
08430     } else if (ret < 0) {
08431         ret = -1;
08432     } else {
08433         ret = 1;
08434     }
08435     xmlRegFreeExecCtxt(exec);
08436 #ifdef DEBUG_PROGRESSIVE
08437     if (ret < 0)
08438         xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
08439                         elem->name);
08440 #endif
08441     return (ret);
08442 }
08443 
08444 /**
08445  * xmlRelaxNGValidateFullElement:
08446  * @ctxt:  the validation context
08447  * @doc:  a document instance
08448  * @elem:  an element instance
08449  *
08450  * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
08451  * 0 and the content of the node has been expanded.
08452  *
08453  * returns 1 if no validation problem was found or -1 in case of error.
08454  */
08455 int
08456 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
08457                               xmlDocPtr doc ATTRIBUTE_UNUSED,
08458                               xmlNodePtr elem)
08459 {
08460     int ret;
08461     xmlRelaxNGValidStatePtr state;
08462 
08463     if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL))
08464         return (-1);
08465 #ifdef DEBUG_PROGRESSIVE
08466     xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
08467 #endif
08468     state = xmlRelaxNGNewValidState(ctxt, elem->parent);
08469     if (state == NULL) {
08470         return (-1);
08471     }
08472     state->seq = elem;
08473     ctxt->state = state;
08474     ctxt->errNo = XML_RELAXNG_OK;
08475     ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
08476     if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK))
08477         ret = -1;
08478     else
08479         ret = 1;
08480     xmlRelaxNGFreeValidState(ctxt, ctxt->state);
08481     ctxt->state = NULL;
08482 #ifdef DEBUG_PROGRESSIVE
08483     if (ret < 0)
08484         xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
08485                         elem->name);
08486 #endif
08487     return (ret);
08488 }
08489 
08490 /************************************************************************
08491  *                                  *
08492  *      Generic interpreted validation implementation       *
08493  *                                  *
08494  ************************************************************************/
08495 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
08496                                    xmlRelaxNGDefinePtr define);
08497 
08498 /**
08499  * xmlRelaxNGSkipIgnored:
08500  * @ctxt:  a schema validation context
08501  * @node:  the top node.
08502  *
08503  * Skip ignorable nodes in that context
08504  *
08505  * Returns the new sibling or NULL in case of error.
08506  */
08507 static xmlNodePtr
08508 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
08509                       xmlNodePtr node)
08510 {
08511     /*
08512      * TODO complete and handle entities
08513      */
08514     while ((node != NULL) &&
08515            ((node->type == XML_COMMENT_NODE) ||
08516             (node->type == XML_PI_NODE) ||
08517         (node->type == XML_XINCLUDE_START) ||
08518         (node->type == XML_XINCLUDE_END) ||
08519             (((node->type == XML_TEXT_NODE) ||
08520               (node->type == XML_CDATA_SECTION_NODE)) &&
08521              ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
08522               (IS_BLANK_NODE(node)))))) {
08523         node = node->next;
08524     }
08525     return (node);
08526 }
08527 
08528 /**
08529  * xmlRelaxNGNormalize:
08530  * @ctxt:  a schema validation context
08531  * @str:  the string to normalize
08532  *
08533  * Implements the  normalizeWhiteSpace( s ) function from
08534  * section 6.2.9 of the spec
08535  *
08536  * Returns the new string or NULL in case of error.
08537  */
08538 static xmlChar *
08539 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar * str)
08540 {
08541     xmlChar *ret, *p;
08542     const xmlChar *tmp;
08543     int len;
08544 
08545     if (str == NULL)
08546         return (NULL);
08547     tmp = str;
08548     while (*tmp != 0)
08549         tmp++;
08550     len = tmp - str;
08551 
08552     ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
08553     if (ret == NULL) {
08554         xmlRngVErrMemory(ctxt, "validating\n");
08555         return (NULL);
08556     }
08557     p = ret;
08558     while (IS_BLANK_CH(*str))
08559         str++;
08560     while (*str != 0) {
08561         if (IS_BLANK_CH(*str)) {
08562             while (IS_BLANK_CH(*str))
08563                 str++;
08564             if (*str == 0)
08565                 break;
08566             *p++ = ' ';
08567         } else
08568             *p++ = *str++;
08569     }
08570     *p = 0;
08571     return (ret);
08572 }
08573 
08574 /**
08575  * xmlRelaxNGValidateDatatype:
08576  * @ctxt:  a Relax-NG validation context
08577  * @value:  the string value
08578  * @type:  the datatype definition
08579  * @node:  the node
08580  *
08581  * Validate the given value against the dataype
08582  *
08583  * Returns 0 if the validation succeeded or an error code.
08584  */
08585 static int
08586 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt,
08587                            const xmlChar * value,
08588                            xmlRelaxNGDefinePtr define, xmlNodePtr node)
08589 {
08590     int ret, tmp;
08591     xmlRelaxNGTypeLibraryPtr lib;
08592     void *result = NULL;
08593     xmlRelaxNGDefinePtr cur;
08594 
08595     if ((define == NULL) || (define->data == NULL)) {
08596         return (-1);
08597     }
08598     lib = (xmlRelaxNGTypeLibraryPtr) define->data;
08599     if (lib->check != NULL) {
08600         if ((define->attrs != NULL) &&
08601             (define->attrs->type == XML_RELAXNG_PARAM)) {
08602             ret =
08603                 lib->check(lib->data, define->name, value, &result, node);
08604         } else {
08605             ret = lib->check(lib->data, define->name, value, NULL, node);
08606         }
08607     } else
08608         ret = -1;
08609     if (ret < 0) {
08610         VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
08611         if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
08612             lib->freef(lib->data, result);
08613         return (-1);
08614     } else if (ret == 1) {
08615         ret = 0;
08616     } else if (ret == 2) {
08617         VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
08618     } else {
08619         VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
08620         ret = -1;
08621     }
08622     cur = define->attrs;
08623     while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
08624         if (lib->facet != NULL) {
08625             tmp = lib->facet(lib->data, define->name, cur->name,
08626                              cur->value, value, result);
08627             if (tmp != 0)
08628                 ret = -1;
08629         }
08630         cur = cur->next;
08631     }
08632     if ((ret == 0) && (define->content != NULL)) {
08633         const xmlChar *oldvalue, *oldendvalue;
08634 
08635         oldvalue = ctxt->state->value;
08636         oldendvalue = ctxt->state->endvalue;
08637         ctxt->state->value = (xmlChar *) value;
08638         ctxt->state->endvalue = NULL;
08639         ret = xmlRelaxNGValidateValue(ctxt, define->content);
08640         ctxt->state->value = (xmlChar *) oldvalue;
08641         ctxt->state->endvalue = (xmlChar *) oldendvalue;
08642     }
08643     if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
08644         lib->freef(lib->data, result);
08645     return (ret);
08646 }
08647 
08648 /**
08649  * xmlRelaxNGNextValue:
08650  * @ctxt:  a Relax-NG validation context
08651  *
08652  * Skip to the next value when validating within a list
08653  *
08654  * Returns 0 if the operation succeeded or an error code.
08655  */
08656 static int
08657 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt)
08658 {
08659     xmlChar *cur;
08660 
08661     cur = ctxt->state->value;
08662     if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
08663         ctxt->state->value = NULL;
08664         ctxt->state->endvalue = NULL;
08665         return (0);
08666     }
08667     while (*cur != 0)
08668         cur++;
08669     while ((cur != ctxt->state->endvalue) && (*cur == 0))
08670         cur++;
08671     if (cur == ctxt->state->endvalue)
08672         ctxt->state->value = NULL;
08673     else
08674         ctxt->state->value = cur;
08675     return (0);
08676 }
08677 
08678 /**
08679  * xmlRelaxNGValidateValueList:
08680  * @ctxt:  a Relax-NG validation context
08681  * @defines:  the list of definitions to verify
08682  *
08683  * Validate the given set of definitions for the current value
08684  *
08685  * Returns 0 if the validation succeeded or an error code.
08686  */
08687 static int
08688 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
08689                             xmlRelaxNGDefinePtr defines)
08690 {
08691     int ret = 0;
08692 
08693     while (defines != NULL) {
08694         ret = xmlRelaxNGValidateValue(ctxt, defines);
08695         if (ret != 0)
08696             break;
08697         defines = defines->next;
08698     }
08699     return (ret);
08700 }
08701 
08702 /**
08703  * xmlRelaxNGValidateValue:
08704  * @ctxt:  a Relax-NG validation context
08705  * @define:  the definition to verify
08706  *
08707  * Validate the given definition for the current value
08708  *
08709  * Returns 0 if the validation succeeded or an error code.
08710  */
08711 static int
08712 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
08713                         xmlRelaxNGDefinePtr define)
08714 {
08715     int ret = 0, oldflags;
08716     xmlChar *value;
08717 
08718     value = ctxt->state->value;
08719     switch (define->type) {
08720         case XML_RELAXNG_EMPTY:{
08721                 if ((value != NULL) && (value[0] != 0)) {
08722                     int idx = 0;
08723 
08724                     while (IS_BLANK_CH(value[idx]))
08725                         idx++;
08726                     if (value[idx] != 0)
08727                         ret = -1;
08728                 }
08729                 break;
08730             }
08731         case XML_RELAXNG_TEXT:
08732             break;
08733         case XML_RELAXNG_VALUE:{
08734                 if (!xmlStrEqual(value, define->value)) {
08735                     if (define->name != NULL) {
08736                         xmlRelaxNGTypeLibraryPtr lib;
08737 
08738                         lib = (xmlRelaxNGTypeLibraryPtr) define->data;
08739                         if ((lib != NULL) && (lib->comp != NULL)) {
08740                             ret = lib->comp(lib->data, define->name,
08741                                             define->value, define->node,
08742                                             (void *) define->attrs,
08743                                             value, ctxt->state->node);
08744                         } else
08745                             ret = -1;
08746                         if (ret < 0) {
08747                             VALID_ERR2(XML_RELAXNG_ERR_TYPECMP,
08748                                        define->name);
08749                             return (-1);
08750                         } else if (ret == 1) {
08751                             ret = 0;
08752                         } else {
08753                             ret = -1;
08754                         }
08755                     } else {
08756                         xmlChar *nval, *nvalue;
08757 
08758                         /*
08759                          * TODO: trivial optimizations are possible by
08760                          * computing at compile-time
08761                          */
08762                         nval = xmlRelaxNGNormalize(ctxt, define->value);
08763                         nvalue = xmlRelaxNGNormalize(ctxt, value);
08764 
08765                         if ((nval == NULL) || (nvalue == NULL) ||
08766                             (!xmlStrEqual(nval, nvalue)))
08767                             ret = -1;
08768                         if (nval != NULL)
08769                             xmlFree(nval);
08770                         if (nvalue != NULL)
08771                             xmlFree(nvalue);
08772                     }
08773                 }
08774                 if (ret == 0)
08775                     xmlRelaxNGNextValue(ctxt);
08776                 break;
08777             }
08778         case XML_RELAXNG_DATATYPE:{
08779                 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
08780                                                  ctxt->state->seq);
08781                 if (ret == 0)
08782                     xmlRelaxNGNextValue(ctxt);
08783 
08784                 break;
08785             }
08786         case XML_RELAXNG_CHOICE:{
08787                 xmlRelaxNGDefinePtr list = define->content;
08788                 xmlChar *oldvalue;
08789 
08790                 oldflags = ctxt->flags;
08791                 ctxt->flags |= FLAGS_IGNORABLE;
08792 
08793                 oldvalue = ctxt->state->value;
08794                 while (list != NULL) {
08795                     ret = xmlRelaxNGValidateValue(ctxt, list);
08796                     if (ret == 0) {
08797                         break;
08798                     }
08799                     ctxt->state->value = oldvalue;
08800                     list = list->next;
08801                 }
08802                 ctxt->flags = oldflags;
08803                 if (ret != 0) {
08804                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
08805                         xmlRelaxNGDumpValidError(ctxt);
08806                 } else {
08807                     if (ctxt->errNr > 0)
08808                         xmlRelaxNGPopErrors(ctxt, 0);
08809                 }
08810                 break;
08811             }
08812         case XML_RELAXNG_LIST:{
08813                 xmlRelaxNGDefinePtr list = define->content;
08814                 xmlChar *oldvalue, *oldend, *val, *cur;
08815 
08816 #ifdef DEBUG_LIST
08817                 int nb_values = 0;
08818 #endif
08819 
08820                 oldvalue = ctxt->state->value;
08821                 oldend = ctxt->state->endvalue;
08822 
08823                 val = xmlStrdup(oldvalue);
08824                 if (val == NULL) {
08825                     val = xmlStrdup(BAD_CAST "");
08826                 }
08827                 if (val == NULL) {
08828                     VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
08829                     return (-1);
08830                 }
08831                 cur = val;
08832                 while (*cur != 0) {
08833                     if (IS_BLANK_CH(*cur)) {
08834                         *cur = 0;
08835                         cur++;
08836 #ifdef DEBUG_LIST
08837                         nb_values++;
08838 #endif
08839                         while (IS_BLANK_CH(*cur))
08840                             *cur++ = 0;
08841                     } else
08842                         cur++;
08843                 }
08844 #ifdef DEBUG_LIST
08845                 xmlGenericError(xmlGenericErrorContext,
08846                                 "list value: '%s' found %d items\n",
08847                                 oldvalue, nb_values);
08848                 nb_values = 0;
08849 #endif
08850                 ctxt->state->endvalue = cur;
08851                 cur = val;
08852                 while ((*cur == 0) && (cur != ctxt->state->endvalue))
08853                     cur++;
08854 
08855                 ctxt->state->value = cur;
08856 
08857                 while (list != NULL) {
08858                     if (ctxt->state->value == ctxt->state->endvalue)
08859                         ctxt->state->value = NULL;
08860                     ret = xmlRelaxNGValidateValue(ctxt, list);
08861                     if (ret != 0) {
08862 #ifdef DEBUG_LIST
08863                         xmlGenericError(xmlGenericErrorContext,
08864                                         "Failed to validate value: '%s' with %d rule\n",
08865                                         ctxt->state->value, nb_values);
08866 #endif
08867                         break;
08868                     }
08869 #ifdef DEBUG_LIST
08870                     nb_values++;
08871 #endif
08872                     list = list->next;
08873                 }
08874 
08875                 if ((ret == 0) && (ctxt->state->value != NULL) &&
08876                     (ctxt->state->value != ctxt->state->endvalue)) {
08877                     VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA,
08878                                ctxt->state->value);
08879                     ret = -1;
08880                 }
08881                 xmlFree(val);
08882                 ctxt->state->value = oldvalue;
08883                 ctxt->state->endvalue = oldend;
08884                 break;
08885             }
08886         case XML_RELAXNG_ONEORMORE:
08887             ret = xmlRelaxNGValidateValueList(ctxt, define->content);
08888             if (ret != 0) {
08889                 break;
08890             }
08891             /* no break on purpose */
08892         case XML_RELAXNG_ZEROORMORE:{
08893                 xmlChar *cur, *temp;
08894 
08895                 if ((ctxt->state->value == NULL) ||
08896                     (*ctxt->state->value == 0)) {
08897                     ret = 0;
08898                     break;
08899                 }
08900                 oldflags = ctxt->flags;
08901                 ctxt->flags |= FLAGS_IGNORABLE;
08902                 cur = ctxt->state->value;
08903                 temp = NULL;
08904                 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
08905                        (temp != cur)) {
08906                     temp = cur;
08907                     ret =
08908                         xmlRelaxNGValidateValueList(ctxt, define->content);
08909                     if (ret != 0) {
08910                         ctxt->state->value = temp;
08911                         ret = 0;
08912                         break;
08913                     }
08914                     cur = ctxt->state->value;
08915                 }
08916                 ctxt->flags = oldflags;
08917         if (ctxt->errNr > 0)
08918             xmlRelaxNGPopErrors(ctxt, 0);
08919                 break;
08920             }
08921         case XML_RELAXNG_OPTIONAL:{
08922                 xmlChar *temp;
08923 
08924                 if ((ctxt->state->value == NULL) ||
08925                     (*ctxt->state->value == 0)) {
08926                     ret = 0;
08927                     break;
08928                 }
08929                 oldflags = ctxt->flags;
08930                 ctxt->flags |= FLAGS_IGNORABLE;
08931                 temp = ctxt->state->value;
08932                 ret = xmlRelaxNGValidateValue(ctxt, define->content);
08933                 ctxt->flags = oldflags;
08934                 if (ret != 0) {
08935                     ctxt->state->value = temp;
08936                     if (ctxt->errNr > 0)
08937                         xmlRelaxNGPopErrors(ctxt, 0);
08938                     ret = 0;
08939                     break;
08940                 }
08941         if (ctxt->errNr > 0)
08942             xmlRelaxNGPopErrors(ctxt, 0);
08943                 break;
08944             }
08945         case XML_RELAXNG_EXCEPT:{
08946                 xmlRelaxNGDefinePtr list;
08947 
08948                 list = define->content;
08949                 while (list != NULL) {
08950                     ret = xmlRelaxNGValidateValue(ctxt, list);
08951                     if (ret == 0) {
08952                         ret = -1;
08953                         break;
08954                     } else
08955                         ret = 0;
08956                     list = list->next;
08957                 }
08958                 break;
08959             }
08960         case XML_RELAXNG_DEF:
08961         case XML_RELAXNG_GROUP:{
08962                 xmlRelaxNGDefinePtr list;
08963 
08964                 list = define->content;
08965                 while (list != NULL) {
08966                     ret = xmlRelaxNGValidateValue(ctxt, list);
08967                     if (ret != 0) {
08968                         ret = -1;
08969                         break;
08970                     } else
08971                         ret = 0;
08972                     list = list->next;
08973                 }
08974                 break;
08975             }
08976         case XML_RELAXNG_REF:
08977         case XML_RELAXNG_PARENTREF:
08978         if (define->content == NULL) {
08979                 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
08980                 ret = -1;
08981         } else {
08982                 ret = xmlRelaxNGValidateValue(ctxt, define->content);
08983             }
08984             break;
08985         default:
08986             TODO ret = -1;
08987     }
08988     return (ret);
08989 }
08990 
08991 /**
08992  * xmlRelaxNGValidateValueContent:
08993  * @ctxt:  a Relax-NG validation context
08994  * @defines:  the list of definitions to verify
08995  *
08996  * Validate the given definitions for the current value
08997  *
08998  * Returns 0 if the validation succeeded or an error code.
08999  */
09000 static int
09001 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
09002                                xmlRelaxNGDefinePtr defines)
09003 {
09004     int ret = 0;
09005 
09006     while (defines != NULL) {
09007         ret = xmlRelaxNGValidateValue(ctxt, defines);
09008         if (ret != 0)
09009             break;
09010         defines = defines->next;
09011     }
09012     return (ret);
09013 }
09014 
09015 /**
09016  * xmlRelaxNGAttributeMatch:
09017  * @ctxt:  a Relax-NG validation context
09018  * @define:  the definition to check
09019  * @prop:  the attribute
09020  *
09021  * Check if the attribute matches the definition nameClass
09022  *
09023  * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
09024  */
09025 static int
09026 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
09027                          xmlRelaxNGDefinePtr define, xmlAttrPtr prop)
09028 {
09029     int ret;
09030 
09031     if (define->name != NULL) {
09032         if (!xmlStrEqual(define->name, prop->name))
09033             return (0);
09034     }
09035     if (define->ns != NULL) {
09036         if (define->ns[0] == 0) {
09037             if (prop->ns != NULL)
09038                 return (0);
09039         } else {
09040             if ((prop->ns == NULL) ||
09041                 (!xmlStrEqual(define->ns, prop->ns->href)))
09042                 return (0);
09043         }
09044     }
09045     if (define->nameClass == NULL)
09046         return (1);
09047     define = define->nameClass;
09048     if (define->type == XML_RELAXNG_EXCEPT) {
09049         xmlRelaxNGDefinePtr list;
09050 
09051         list = define->content;
09052         while (list != NULL) {
09053             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
09054             if (ret == 1)
09055                 return (0);
09056             if (ret < 0)
09057                 return (ret);
09058             list = list->next;
09059         }
09060     } else if (define->type == XML_RELAXNG_CHOICE) {
09061         xmlRelaxNGDefinePtr list;
09062 
09063         list = define->nameClass;
09064         while (list != NULL) {
09065             ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
09066             if (ret == 1)
09067                 return (1);
09068             if (ret < 0)
09069                 return (ret);
09070             list = list->next;
09071         }
09072         return (0);
09073     } else {
09074     TODO}
09075     return (1);
09076 }
09077 
09078 /**
09079  * xmlRelaxNGValidateAttribute:
09080  * @ctxt:  a Relax-NG validation context
09081  * @define:  the definition to verify
09082  *
09083  * Validate the given attribute definition for that node
09084  *
09085  * Returns 0 if the validation succeeded or an error code.
09086  */
09087 static int
09088 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
09089                             xmlRelaxNGDefinePtr define)
09090 {
09091     int ret = 0, i;
09092     xmlChar *value, *oldvalue;
09093     xmlAttrPtr prop = NULL, tmp;
09094     xmlNodePtr oldseq;
09095 
09096     if (ctxt->state->nbAttrLeft <= 0)
09097         return (-1);
09098     if (define->name != NULL) {
09099         for (i = 0; i < ctxt->state->nbAttrs; i++) {
09100             tmp = ctxt->state->attrs[i];
09101             if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
09102                 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
09103                      (tmp->ns == NULL)) ||
09104                     ((tmp->ns != NULL) &&
09105                      (xmlStrEqual(define->ns, tmp->ns->href)))) {
09106                     prop = tmp;
09107                     break;
09108                 }
09109             }
09110         }
09111         if (prop != NULL) {
09112             value = xmlNodeListGetString(prop->doc, prop->children, 1);
09113             oldvalue = ctxt->state->value;
09114             oldseq = ctxt->state->seq;
09115             ctxt->state->seq = (xmlNodePtr) prop;
09116             ctxt->state->value = value;
09117             ctxt->state->endvalue = NULL;
09118             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
09119             if (ctxt->state->value != NULL)
09120                 value = ctxt->state->value;
09121             if (value != NULL)
09122                 xmlFree(value);
09123             ctxt->state->value = oldvalue;
09124             ctxt->state->seq = oldseq;
09125             if (ret == 0) {
09126                 /*
09127                  * flag the attribute as processed
09128                  */
09129                 ctxt->state->attrs[i] = NULL;
09130                 ctxt->state->nbAttrLeft--;
09131             }
09132         } else {
09133             ret = -1;
09134         }
09135 #ifdef DEBUG
09136         xmlGenericError(xmlGenericErrorContext,
09137                         "xmlRelaxNGValidateAttribute(%s): %d\n",
09138                         define->name, ret);
09139 #endif
09140     } else {
09141         for (i = 0; i < ctxt->state->nbAttrs; i++) {
09142             tmp = ctxt->state->attrs[i];
09143             if ((tmp != NULL) &&
09144                 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
09145                 prop = tmp;
09146                 break;
09147             }
09148         }
09149         if (prop != NULL) {
09150             value = xmlNodeListGetString(prop->doc, prop->children, 1);
09151             oldvalue = ctxt->state->value;
09152             oldseq = ctxt->state->seq;
09153             ctxt->state->seq = (xmlNodePtr) prop;
09154             ctxt->state->value = value;
09155             ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
09156             if (ctxt->state->value != NULL)
09157                 value = ctxt->state->value;
09158             if (value != NULL)
09159                 xmlFree(value);
09160             ctxt->state->value = oldvalue;
09161             ctxt->state->seq = oldseq;
09162             if (ret == 0) {
09163                 /*
09164                  * flag the attribute as processed
09165                  */
09166                 ctxt->state->attrs[i] = NULL;
09167                 ctxt->state->nbAttrLeft--;
09168             }
09169         } else {
09170             ret = -1;
09171         }
09172 #ifdef DEBUG
09173         if (define->ns != NULL) {
09174             xmlGenericError(xmlGenericErrorContext,
09175                             "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
09176                             define->ns, ret);
09177         } else {
09178             xmlGenericError(xmlGenericErrorContext,
09179                             "xmlRelaxNGValidateAttribute(anyName): %d\n",
09180                             ret);
09181         }
09182 #endif
09183     }
09184 
09185     return (ret);
09186 }
09187 
09188 /**
09189  * xmlRelaxNGValidateAttributeList:
09190  * @ctxt:  a Relax-NG validation context
09191  * @define:  the list of definition to verify
09192  *
09193  * Validate the given node against the list of attribute definitions
09194  *
09195  * Returns 0 if the validation succeeded or an error code.
09196  */
09197 static int
09198 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
09199                                 xmlRelaxNGDefinePtr defines)
09200 {
09201     int ret = 0, res;
09202     int needmore = 0;
09203     xmlRelaxNGDefinePtr cur;
09204 
09205     cur = defines;
09206     while (cur != NULL) {
09207         if (cur->type == XML_RELAXNG_ATTRIBUTE) {
09208             if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
09209                 ret = -1;
09210         } else
09211             needmore = 1;
09212         cur = cur->next;
09213     }
09214     if (!needmore)
09215         return (ret);
09216     cur = defines;
09217     while (cur != NULL) {
09218         if (cur->type != XML_RELAXNG_ATTRIBUTE) {
09219             if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
09220                 res = xmlRelaxNGValidateDefinition(ctxt, cur);
09221                 if (res < 0)
09222                     ret = -1;
09223             } else {
09224                 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
09225                 return (-1);
09226             }
09227             if (res == -1)      /* continues on -2 */
09228                 break;
09229         }
09230         cur = cur->next;
09231     }
09232 
09233     return (ret);
09234 }
09235 
09236 /**
09237  * xmlRelaxNGNodeMatchesList:
09238  * @node:  the node
09239  * @list:  a NULL terminated array of definitions
09240  *
09241  * Check if a node can be matched by one of the definitions
09242  *
09243  * Returns 1 if matches 0 otherwise
09244  */
09245 static int
09246 xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr * list)
09247 {
09248     xmlRelaxNGDefinePtr cur;
09249     int i = 0, tmp;
09250 
09251     if ((node == NULL) || (list == NULL))
09252         return (0);
09253 
09254     cur = list[i++];
09255     while (cur != NULL) {
09256         if ((node->type == XML_ELEMENT_NODE) &&
09257             (cur->type == XML_RELAXNG_ELEMENT)) {
09258             tmp = xmlRelaxNGElementMatch(NULL, cur, node);
09259             if (tmp == 1)
09260                 return (1);
09261         } else if (((node->type == XML_TEXT_NODE) ||
09262                     (node->type == XML_CDATA_SECTION_NODE)) &&
09263                    (cur->type == XML_RELAXNG_TEXT)) {
09264             return (1);
09265         }
09266         cur = list[i++];
09267     }
09268     return (0);
09269 }
09270 
09271 /**
09272  * xmlRelaxNGValidateInterleave:
09273  * @ctxt:  a Relax-NG validation context
09274  * @define:  the definition to verify
09275  *
09276  * Validate an interleave definition for a node.
09277  *
09278  * Returns 0 if the validation succeeded or an error code.
09279  */
09280 static int
09281 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
09282                              xmlRelaxNGDefinePtr define)
09283 {
09284     int ret = 0, i, nbgroups;
09285     int errNr = ctxt->errNr;
09286     int oldflags;
09287 
09288     xmlRelaxNGValidStatePtr oldstate;
09289     xmlRelaxNGPartitionPtr partitions;
09290     xmlRelaxNGInterleaveGroupPtr group = NULL;
09291     xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
09292     xmlNodePtr *list = NULL, *lasts = NULL;
09293 
09294     if (define->data != NULL) {
09295         partitions = (xmlRelaxNGPartitionPtr) define->data;
09296         nbgroups = partitions->nbgroups;
09297     } else {
09298         VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
09299         return (-1);
09300     }
09301     /*
09302      * Optimizations for MIXED
09303      */
09304     oldflags = ctxt->flags;
09305     if (define->dflags & IS_MIXED) {
09306         ctxt->flags |= FLAGS_MIXED_CONTENT;
09307         if (nbgroups == 2) {
09308             /*
09309              * this is a pure <mixed> case
09310              */
09311             if (ctxt->state != NULL)
09312                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
09313                                                          ctxt->state->seq);
09314             if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
09315                 ret = xmlRelaxNGValidateDefinition(ctxt,
09316                                                    partitions->groups[1]->
09317                                                    rule);
09318             else
09319                 ret = xmlRelaxNGValidateDefinition(ctxt,
09320                                                    partitions->groups[0]->
09321                                                    rule);
09322             if (ret == 0) {
09323                 if (ctxt->state != NULL)
09324                     ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
09325                                                              ctxt->state->
09326                                                              seq);
09327             }
09328             ctxt->flags = oldflags;
09329             return (ret);
09330         }
09331     }
09332 
09333     /*
09334      * Build arrays to store the first and last node of the chain
09335      * pertaining to each group
09336      */
09337     list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
09338     if (list == NULL) {
09339         xmlRngVErrMemory(ctxt, "validating\n");
09340         return (-1);
09341     }
09342     memset(list, 0, nbgroups * sizeof(xmlNodePtr));
09343     lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
09344     if (lasts == NULL) {
09345         xmlRngVErrMemory(ctxt, "validating\n");
09346         return (-1);
09347     }
09348     memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
09349 
09350     /*
09351      * Walk the sequence of children finding the right group and
09352      * sorting them in sequences.
09353      */
09354     cur = ctxt->state->seq;
09355     cur = xmlRelaxNGSkipIgnored(ctxt, cur);
09356     start = cur;
09357     while (cur != NULL) {
09358         ctxt->state->seq = cur;
09359         if ((partitions->triage != NULL) &&
09360             (partitions->flags & IS_DETERMINIST)) {
09361             void *tmp = NULL;
09362 
09363             if ((cur->type == XML_TEXT_NODE) ||
09364                 (cur->type == XML_CDATA_SECTION_NODE)) {
09365                 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
09366                                      NULL);
09367             } else if (cur->type == XML_ELEMENT_NODE) {
09368                 if (cur->ns != NULL) {
09369                     tmp = xmlHashLookup2(partitions->triage, cur->name,
09370                                          cur->ns->href);
09371                     if (tmp == NULL)
09372                         tmp = xmlHashLookup2(partitions->triage,
09373                                              BAD_CAST "#any",
09374                                              cur->ns->href);
09375                 } else
09376                     tmp =
09377                         xmlHashLookup2(partitions->triage, cur->name,
09378                                        NULL);
09379                 if (tmp == NULL)
09380                     tmp =
09381                         xmlHashLookup2(partitions->triage, BAD_CAST "#any",
09382                                        NULL);
09383             }
09384 
09385             if (tmp == NULL) {
09386                 i = nbgroups;
09387             } else {
09388                 i = ((long) tmp) - 1;
09389                 if (partitions->flags & IS_NEEDCHECK) {
09390                     group = partitions->groups[i];
09391                     if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
09392                         i = nbgroups;
09393                 }
09394             }
09395         } else {
09396             for (i = 0; i < nbgroups; i++) {
09397                 group = partitions->groups[i];
09398                 if (group == NULL)
09399                     continue;
09400                 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
09401                     break;
09402             }
09403         }
09404         /*
09405          * We break as soon as an element not matched is found
09406          */
09407         if (i >= nbgroups) {
09408             break;
09409         }
09410         if (lasts[i] != NULL) {
09411             lasts[i]->next = cur;
09412             lasts[i] = cur;
09413         } else {
09414             list[i] = cur;
09415             lasts[i] = cur;
09416         }
09417         if (cur->next != NULL)
09418             lastchg = cur->next;
09419         else
09420             lastchg = cur;
09421         cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
09422     }
09423     if (ret != 0) {
09424         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
09425         ret = -1;
09426         goto done;
09427     }
09428     lastelem = cur;
09429     oldstate = ctxt->state;
09430     for (i = 0; i < nbgroups; i++) {
09431         ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
09432     if (ctxt->state == NULL) {
09433         ret = -1;
09434         break;
09435     }
09436         group = partitions->groups[i];
09437         if (lasts[i] != NULL) {
09438             last = lasts[i]->next;
09439             lasts[i]->next = NULL;
09440         }
09441         ctxt->state->seq = list[i];
09442         ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
09443         if (ret != 0)
09444             break;
09445         if (ctxt->state != NULL) {
09446             cur = ctxt->state->seq;
09447             cur = xmlRelaxNGSkipIgnored(ctxt, cur);
09448             xmlRelaxNGFreeValidState(ctxt, oldstate);
09449             oldstate = ctxt->state;
09450             ctxt->state = NULL;
09451             if (cur != NULL) {
09452                 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
09453                 ret = -1;
09454                 ctxt->state = oldstate;
09455                 goto done;
09456             }
09457         } else if (ctxt->states != NULL) {
09458             int j;
09459             int found = 0;
09460         int best = -1;
09461         int lowattr = -1;
09462 
09463         /*
09464          * PBM: what happen if there is attributes checks in the interleaves
09465          */
09466 
09467             for (j = 0; j < ctxt->states->nbState; j++) {
09468                 cur = ctxt->states->tabState[j]->seq;
09469                 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
09470                 if (cur == NULL) {
09471             if (found == 0) {
09472                 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
09473             best = j;
09474             }
09475                     found = 1;
09476             if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr) {
09477                 /* try  to keep the latest one to mach old heuristic */
09478                 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
09479             best = j;
09480             }
09481                     if (lowattr == 0)
09482                 break;
09483                 } else if (found == 0) {
09484                     if (lowattr == -1) {
09485                 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
09486             best = j;
09487             } else
09488             if (ctxt->states->tabState[j]->nbAttrLeft <= lowattr)  {
09489                 /* try  to keep the latest one to mach old heuristic */
09490                 lowattr = ctxt->states->tabState[j]->nbAttrLeft;
09491             best = j;
09492             }
09493         }
09494             }
09495         /*
09496          * BIG PBM: here we pick only one restarting point :-(
09497          */
09498             if (ctxt->states->nbState > 0) {
09499                 xmlRelaxNGFreeValidState(ctxt, oldstate);
09500         if (best != -1) {
09501             oldstate = ctxt->states->tabState[best];
09502             ctxt->states->tabState[best] = NULL;
09503         } else {
09504             oldstate =
09505             ctxt->states->tabState[ctxt->states->nbState - 1];
09506                     ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
09507                     ctxt->states->nbState--;
09508         }
09509             }
09510             for (j = 0; j < ctxt->states->nbState ; j++) {
09511                 xmlRelaxNGFreeValidState(ctxt, ctxt->states->tabState[j]);
09512             }
09513             xmlRelaxNGFreeStates(ctxt, ctxt->states);
09514             ctxt->states = NULL;
09515             if (found == 0) {
09516                 if (cur == NULL) {
09517             VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA,
09518                    (const xmlChar *) "noname");
09519                 } else {
09520                     VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
09521                 }
09522                 ret = -1;
09523                 ctxt->state = oldstate;
09524                 goto done;
09525             }
09526         } else {
09527             ret = -1;
09528             break;
09529         }
09530         if (lasts[i] != NULL) {
09531             lasts[i]->next = last;
09532         }
09533     }
09534     if (ctxt->state != NULL)
09535         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
09536     ctxt->state = oldstate;
09537     ctxt->state->seq = lastelem;
09538     if (ret != 0) {
09539         VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
09540         ret = -1;
09541         goto done;
09542     }
09543 
09544   done:
09545     ctxt->flags = oldflags;
09546     /*
09547      * builds the next links chain from the prev one
09548      */
09549     cur = lastchg;
09550     while (cur != NULL) {
09551         if ((cur == start) || (cur->prev == NULL))
09552             break;
09553         cur->prev->next = cur;
09554         cur = cur->prev;
09555     }
09556     if (ret == 0) {
09557         if (ctxt->errNr > errNr)
09558             xmlRelaxNGPopErrors(ctxt, errNr);
09559     }
09560 
09561     xmlFree(list);
09562     xmlFree(lasts);
09563     return (ret);
09564 }
09565 
09566 /**
09567  * xmlRelaxNGValidateDefinitionList:
09568  * @ctxt:  a Relax-NG validation context
09569  * @define:  the list of definition to verify
09570  *
09571  * Validate the given node content against the (list) of definitions
09572  *
09573  * Returns 0 if the validation succeeded or an error code.
09574  */
09575 static int
09576 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
09577                                  xmlRelaxNGDefinePtr defines)
09578 {
09579     int ret = 0, res;
09580 
09581 
09582     if (defines == NULL) {
09583         VALID_ERR2(XML_RELAXNG_ERR_INTERNAL,
09584                    BAD_CAST "NULL definition list");
09585         return (-1);
09586     }
09587     while (defines != NULL) {
09588         if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
09589             res = xmlRelaxNGValidateDefinition(ctxt, defines);
09590             if (res < 0)
09591                 ret = -1;
09592         } else {
09593             VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
09594             return (-1);
09595         }
09596         if (res == -1)          /* continues on -2 */
09597             break;
09598         defines = defines->next;
09599     }
09600 
09601     return (ret);
09602 }
09603 
09604 /**
09605  * xmlRelaxNGElementMatch:
09606  * @ctxt:  a Relax-NG validation context
09607  * @define:  the definition to check
09608  * @elem:  the element
09609  *
09610  * Check if the element matches the definition nameClass
09611  *
09612  * Returns 1 if the element matches, 0 if no, or -1 in case of error
09613  */
09614 static int
09615 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
09616                        xmlRelaxNGDefinePtr define, xmlNodePtr elem)
09617 {
09618     int ret = 0, oldflags = 0;
09619 
09620     if (define->name != NULL) {
09621         if (!xmlStrEqual(elem->name, define->name)) {
09622             VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
09623             return (0);
09624         }
09625     }
09626     if ((define->ns != NULL) && (define->ns[0] != 0)) {
09627         if (elem->ns == NULL) {
09628             VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS, elem->name);
09629             return (0);
09630         } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
09631             VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
09632                        elem->name, define->ns);
09633             return (0);
09634         }
09635     } else if ((elem->ns != NULL) && (define->ns != NULL) &&
09636                (define->name == NULL)) {
09637         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, elem->name);
09638         return (0);
09639     } else if ((elem->ns != NULL) && (define->name != NULL)) {
09640         VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS, define->name);
09641         return (0);
09642     }
09643 
09644     if (define->nameClass == NULL)
09645         return (1);
09646 
09647     define = define->nameClass;
09648     if (define->type == XML_RELAXNG_EXCEPT) {
09649         xmlRelaxNGDefinePtr list;
09650 
09651         if (ctxt != NULL) {
09652             oldflags = ctxt->flags;
09653             ctxt->flags |= FLAGS_IGNORABLE;
09654         }
09655 
09656         list = define->content;
09657         while (list != NULL) {
09658             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
09659             if (ret == 1) {
09660                 if (ctxt != NULL)
09661                     ctxt->flags = oldflags;
09662                 return (0);
09663             }
09664             if (ret < 0) {
09665                 if (ctxt != NULL)
09666                     ctxt->flags = oldflags;
09667                 return (ret);
09668             }
09669             list = list->next;
09670         }
09671         ret = 1;
09672         if (ctxt != NULL) {
09673             ctxt->flags = oldflags;
09674         }
09675     } else if (define->type == XML_RELAXNG_CHOICE) {
09676         xmlRelaxNGDefinePtr list;
09677 
09678         if (ctxt != NULL) {
09679             oldflags = ctxt->flags;
09680             ctxt->flags |= FLAGS_IGNORABLE;
09681         }
09682 
09683         list = define->nameClass;
09684         while (list != NULL) {
09685             ret = xmlRelaxNGElementMatch(ctxt, list, elem);
09686             if (ret == 1) {
09687                 if (ctxt != NULL)
09688                     ctxt->flags = oldflags;
09689                 return (1);
09690             }
09691             if (ret < 0) {
09692                 if (ctxt != NULL)
09693                     ctxt->flags = oldflags;
09694                 return (ret);
09695             }
09696             list = list->next;
09697         }
09698         if (ctxt != NULL) {
09699             if (ret != 0) {
09700                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
09701                     xmlRelaxNGDumpValidError(ctxt);
09702             } else {
09703                 if (ctxt->errNr > 0)
09704                     xmlRelaxNGPopErrors(ctxt, 0);
09705             }
09706         }
09707         ret = 0;
09708         if (ctxt != NULL) {
09709             ctxt->flags = oldflags;
09710         }
09711     } else {
09712         TODO ret = -1;
09713     }
09714     return (ret);
09715 }
09716 
09717 /**
09718  * xmlRelaxNGBestState:
09719  * @ctxt:  a Relax-NG validation context
09720  *
09721  * Find the "best" state in the ctxt->states list of states to report
09722  * errors about. I.e. a state with no element left in the child list
09723  * or the one with the less attributes left.
09724  * This is called only if a falidation error was detected
09725  *
09726  * Returns the index of the "best" state or -1 in case of error
09727  */
09728 static int
09729 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt)
09730 {
09731     xmlRelaxNGValidStatePtr state;
09732     int i, tmp;
09733     int best = -1;
09734     int value = 1000000;
09735 
09736     if ((ctxt == NULL) || (ctxt->states == NULL) ||
09737         (ctxt->states->nbState <= 0))
09738         return (-1);
09739 
09740     for (i = 0; i < ctxt->states->nbState; i++) {
09741         state = ctxt->states->tabState[i];
09742         if (state == NULL)
09743             continue;
09744         if (state->seq != NULL) {
09745             if ((best == -1) || (value > 100000)) {
09746                 value = 100000;
09747                 best = i;
09748             }
09749         } else {
09750             tmp = state->nbAttrLeft;
09751             if ((best == -1) || (value > tmp)) {
09752                 value = tmp;
09753                 best = i;
09754             }
09755         }
09756     }
09757     return (best);
09758 }
09759 
09760 /**
09761  * xmlRelaxNGLogBestError:
09762  * @ctxt:  a Relax-NG validation context
09763  *
09764  * Find the "best" state in the ctxt->states list of states to report
09765  * errors about and log it.
09766  */
09767 static void
09768 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt)
09769 {
09770     int best;
09771 
09772     if ((ctxt == NULL) || (ctxt->states == NULL) ||
09773         (ctxt->states->nbState <= 0))
09774         return;
09775 
09776     best = xmlRelaxNGBestState(ctxt);
09777     if ((best >= 0) && (best < ctxt->states->nbState)) {
09778         ctxt->state = ctxt->states->tabState[best];
09779 
09780         xmlRelaxNGValidateElementEnd(ctxt, 1);
09781     }
09782 }
09783 
09784 /**
09785  * xmlRelaxNGValidateElementEnd:
09786  * @ctxt:  a Relax-NG validation context
09787  * @dolog:  indicate that error logging should be done
09788  *
09789  * Validate the end of the element, implements check that
09790  * there is nothing left not consumed in the element content
09791  * or in the attribute list.
09792  *
09793  * Returns 0 if the validation succeeded or an error code.
09794  */
09795 static int
09796 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt, int dolog)
09797 {
09798     int i;
09799     xmlRelaxNGValidStatePtr state;
09800 
09801     state = ctxt->state;
09802     if (state->seq != NULL) {
09803         state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
09804         if (state->seq != NULL) {
09805             if (dolog) {
09806                 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
09807                            state->node->name, state->seq->name);
09808             }
09809             return (-1);
09810         }
09811     }
09812     for (i = 0; i < state->nbAttrs; i++) {
09813         if (state->attrs[i] != NULL) {
09814             if (dolog) {
09815                 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
09816                            state->attrs[i]->name, state->node->name);
09817             }
09818             return (-1 - i);
09819         }
09820     }
09821     return (0);
09822 }
09823 
09824 /**
09825  * xmlRelaxNGValidateState:
09826  * @ctxt:  a Relax-NG validation context
09827  * @define:  the definition to verify
09828  *
09829  * Validate the current state against the definition
09830  *
09831  * Returns 0 if the validation succeeded or an error code.
09832  */
09833 static int
09834 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
09835                         xmlRelaxNGDefinePtr define)
09836 {
09837     xmlNodePtr node;
09838     int ret = 0, i, tmp, oldflags, errNr;
09839     xmlRelaxNGValidStatePtr oldstate = NULL, state;
09840 
09841     if (define == NULL) {
09842         VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
09843         return (-1);
09844     }
09845 
09846     if (ctxt->state != NULL) {
09847         node = ctxt->state->seq;
09848     } else {
09849         node = NULL;
09850     }
09851 #ifdef DEBUG
09852     for (i = 0; i < ctxt->depth; i++)
09853         xmlGenericError(xmlGenericErrorContext, " ");
09854     xmlGenericError(xmlGenericErrorContext,
09855                     "Start validating %s ", xmlRelaxNGDefName(define));
09856     if (define->name != NULL)
09857         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
09858     if ((node != NULL) && (node->name != NULL))
09859         xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
09860     else
09861         xmlGenericError(xmlGenericErrorContext, "\n");
09862 #endif
09863     ctxt->depth++;
09864     switch (define->type) {
09865         case XML_RELAXNG_EMPTY:
09866             xmlRelaxNGSkipIgnored(ctxt, node);
09867             ret = 0;
09868             break;
09869         case XML_RELAXNG_NOT_ALLOWED:
09870             ret = -1;
09871             break;
09872         case XML_RELAXNG_TEXT:
09873             while ((node != NULL) &&
09874                    ((node->type == XML_TEXT_NODE) ||
09875                     (node->type == XML_COMMENT_NODE) ||
09876                     (node->type == XML_PI_NODE) ||
09877                     (node->type == XML_CDATA_SECTION_NODE)))
09878                 node = node->next;
09879             ctxt->state->seq = node;
09880             break;
09881         case XML_RELAXNG_ELEMENT:
09882             errNr = ctxt->errNr;
09883             node = xmlRelaxNGSkipIgnored(ctxt, node);
09884             if (node == NULL) {
09885                 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
09886                 ret = -1;
09887                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
09888                     xmlRelaxNGDumpValidError(ctxt);
09889                 break;
09890             }
09891             if (node->type != XML_ELEMENT_NODE) {
09892                 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
09893                 ret = -1;
09894                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
09895                     xmlRelaxNGDumpValidError(ctxt);
09896                 break;
09897             }
09898             /*
09899              * This node was already validated successfully against
09900              * this definition.
09901              */
09902             if (node->psvi == define) {
09903                 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
09904                 if (ctxt->errNr > errNr)
09905                     xmlRelaxNGPopErrors(ctxt, errNr);
09906                 if (ctxt->errNr != 0) {
09907                     while ((ctxt->err != NULL) &&
09908                            (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
09909                              && (xmlStrEqual(ctxt->err->arg2, node->name)))
09910                             ||
09911                             ((ctxt->err->err ==
09912                               XML_RELAXNG_ERR_ELEMEXTRANS)
09913                              && (xmlStrEqual(ctxt->err->arg1, node->name)))
09914                             || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
09915                             || (ctxt->err->err ==
09916                                 XML_RELAXNG_ERR_NOTELEM)))
09917                         xmlRelaxNGValidErrorPop(ctxt);
09918                 }
09919                 break;
09920             }
09921 
09922             ret = xmlRelaxNGElementMatch(ctxt, define, node);
09923             if (ret <= 0) {
09924                 ret = -1;
09925                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
09926                     xmlRelaxNGDumpValidError(ctxt);
09927                 break;
09928             }
09929             ret = 0;
09930             if (ctxt->errNr != 0) {
09931                 if (ctxt->errNr > errNr)
09932                     xmlRelaxNGPopErrors(ctxt, errNr);
09933                 while ((ctxt->err != NULL) &&
09934                        (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
09935                          (xmlStrEqual(ctxt->err->arg2, node->name))) ||
09936                         ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
09937                          (xmlStrEqual(ctxt->err->arg1, node->name))) ||
09938                         (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
09939                         (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
09940                     xmlRelaxNGValidErrorPop(ctxt);
09941             }
09942             errNr = ctxt->errNr;
09943 
09944             oldflags = ctxt->flags;
09945             if (ctxt->flags & FLAGS_MIXED_CONTENT) {
09946                 ctxt->flags -= FLAGS_MIXED_CONTENT;
09947             }
09948             state = xmlRelaxNGNewValidState(ctxt, node);
09949             if (state == NULL) {
09950                 ret = -1;
09951                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
09952                     xmlRelaxNGDumpValidError(ctxt);
09953                 break;
09954             }
09955 
09956             oldstate = ctxt->state;
09957             ctxt->state = state;
09958             if (define->attrs != NULL) {
09959                 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
09960                 if (tmp != 0) {
09961                     ret = -1;
09962                     VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
09963                 }
09964             }
09965             if (define->contModel != NULL) {
09966                 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
09967                 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
09968                 xmlNodePtr nseq;
09969 
09970                 nstate = xmlRelaxNGNewValidState(ctxt, node);
09971                 ctxt->state = nstate;
09972                 ctxt->states = NULL;
09973 
09974                 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
09975                                                         define->contModel,
09976                                                         ctxt->state->seq);
09977                 nseq = ctxt->state->seq;
09978                 ctxt->state = tmpstate;
09979                 ctxt->states = tmpstates;
09980                 xmlRelaxNGFreeValidState(ctxt, nstate);
09981 
09982 #ifdef DEBUG_COMPILE
09983                 xmlGenericError(xmlGenericErrorContext,
09984                                 "Validating content of '%s' : %d\n",
09985                                 define->name, tmp);
09986 #endif
09987                 if (tmp != 0)
09988                     ret = -1;
09989 
09990                 if (ctxt->states != NULL) {
09991                     tmp = -1;
09992 
09993                     for (i = 0; i < ctxt->states->nbState; i++) {
09994                         state = ctxt->states->tabState[i];
09995                         ctxt->state = state;
09996                         ctxt->state->seq = nseq;
09997 
09998                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
09999                             tmp = 0;
10000                             break;
10001                         }
10002                     }
10003                     if (tmp != 0) {
10004                         /*
10005                          * validation error, log the message for the "best" one
10006                          */
10007                         ctxt->flags |= FLAGS_IGNORABLE;
10008                         xmlRelaxNGLogBestError(ctxt);
10009                     }
10010                     for (i = 0; i < ctxt->states->nbState; i++) {
10011                         xmlRelaxNGFreeValidState(ctxt,
10012                                                  ctxt->states->
10013                                                  tabState[i]);
10014                     }
10015                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10016                     ctxt->flags = oldflags;
10017                     ctxt->states = NULL;
10018                     if ((ret == 0) && (tmp == -1))
10019                         ret = -1;
10020                 } else {
10021                     state = ctxt->state;
10022             if (ctxt->state != NULL)
10023             ctxt->state->seq = nseq;
10024                     if (ret == 0)
10025                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
10026                     xmlRelaxNGFreeValidState(ctxt, state);
10027                 }
10028             } else {
10029                 if (define->content != NULL) {
10030                     tmp = xmlRelaxNGValidateDefinitionList(ctxt,
10031                                                            define->
10032                                                            content);
10033                     if (tmp != 0) {
10034                         ret = -1;
10035                         if (ctxt->state == NULL) {
10036                             ctxt->state = oldstate;
10037                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
10038                                        node->name);
10039                             ctxt->state = NULL;
10040                         } else {
10041                             VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
10042                                        node->name);
10043                         }
10044 
10045                     }
10046                 }
10047                 if (ctxt->states != NULL) {
10048                     tmp = -1;
10049 
10050                     for (i = 0; i < ctxt->states->nbState; i++) {
10051                         state = ctxt->states->tabState[i];
10052                         ctxt->state = state;
10053 
10054                         if (xmlRelaxNGValidateElementEnd(ctxt, 0) == 0) {
10055                             tmp = 0;
10056                             break;
10057                         }
10058                     }
10059                     if (tmp != 0) {
10060                         /*
10061                          * validation error, log the message for the "best" one
10062                          */
10063                         ctxt->flags |= FLAGS_IGNORABLE;
10064                         xmlRelaxNGLogBestError(ctxt);
10065                     }
10066                     for (i = 0; i < ctxt->states->nbState; i++) {
10067                         xmlRelaxNGFreeValidState(ctxt,
10068                                                  ctxt->states->tabState[i]);
10069                         ctxt->states->tabState[i] = NULL;
10070                     }
10071                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10072                     ctxt->flags = oldflags;
10073                     ctxt->states = NULL;
10074                     if ((ret == 0) && (tmp == -1))
10075                         ret = -1;
10076                 } else {
10077                     state = ctxt->state;
10078                     if (ret == 0)
10079                         ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
10080                     xmlRelaxNGFreeValidState(ctxt, state);
10081                 }
10082             }
10083             if (ret == 0) {
10084                 node->psvi = define;
10085             }
10086             ctxt->flags = oldflags;
10087             ctxt->state = oldstate;
10088             if (oldstate != NULL)
10089                 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
10090             if (ret != 0) {
10091                 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10092                     xmlRelaxNGDumpValidError(ctxt);
10093                     ret = 0;
10094 #if 0
10095                 } else {
10096                     ret = -2;
10097 #endif
10098                 }
10099             } else {
10100                 if (ctxt->errNr > errNr)
10101                     xmlRelaxNGPopErrors(ctxt, errNr);
10102             }
10103 
10104 #ifdef DEBUG
10105             xmlGenericError(xmlGenericErrorContext,
10106                             "xmlRelaxNGValidateDefinition(): validated %s : %d",
10107                             node->name, ret);
10108             if (oldstate == NULL)
10109                 xmlGenericError(xmlGenericErrorContext, ": no state\n");
10110             else if (oldstate->seq == NULL)
10111                 xmlGenericError(xmlGenericErrorContext, ": done\n");
10112             else if (oldstate->seq->type == XML_ELEMENT_NODE)
10113                 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
10114                                 oldstate->seq->name);
10115             else
10116                 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
10117                                 oldstate->seq->name, oldstate->seq->type);
10118 #endif
10119             break;
10120         case XML_RELAXNG_OPTIONAL:{
10121                 errNr = ctxt->errNr;
10122                 oldflags = ctxt->flags;
10123                 ctxt->flags |= FLAGS_IGNORABLE;
10124                 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10125                 ret =
10126                     xmlRelaxNGValidateDefinitionList(ctxt,
10127                                                      define->content);
10128                 if (ret != 0) {
10129                     if (ctxt->state != NULL)
10130                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10131                     ctxt->state = oldstate;
10132                     ctxt->flags = oldflags;
10133                     ret = 0;
10134                     if (ctxt->errNr > errNr)
10135                         xmlRelaxNGPopErrors(ctxt, errNr);
10136                     break;
10137                 }
10138                 if (ctxt->states != NULL) {
10139                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10140                 } else {
10141                     ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
10142                     if (ctxt->states == NULL) {
10143                         xmlRelaxNGFreeValidState(ctxt, oldstate);
10144                         ctxt->flags = oldflags;
10145                         ret = -1;
10146                         if (ctxt->errNr > errNr)
10147                             xmlRelaxNGPopErrors(ctxt, errNr);
10148                         break;
10149                     }
10150                     xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
10151                     xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
10152                     ctxt->state = NULL;
10153                 }
10154                 ctxt->flags = oldflags;
10155                 ret = 0;
10156                 if (ctxt->errNr > errNr)
10157                     xmlRelaxNGPopErrors(ctxt, errNr);
10158                 break;
10159             }
10160         case XML_RELAXNG_ONEORMORE:
10161             errNr = ctxt->errNr;
10162             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10163             if (ret != 0) {
10164                 break;
10165             }
10166             if (ctxt->errNr > errNr)
10167                 xmlRelaxNGPopErrors(ctxt, errNr);
10168             /* no break on purpose */
10169         case XML_RELAXNG_ZEROORMORE:{
10170                 int progress;
10171                 xmlRelaxNGStatesPtr states = NULL, res = NULL;
10172                 int base, j;
10173 
10174                 errNr = ctxt->errNr;
10175                 res = xmlRelaxNGNewStates(ctxt, 1);
10176                 if (res == NULL) {
10177                     ret = -1;
10178                     break;
10179                 }
10180                 /*
10181                  * All the input states are also exit states
10182                  */
10183                 if (ctxt->state != NULL) {
10184                     xmlRelaxNGAddStates(ctxt, res,
10185                                         xmlRelaxNGCopyValidState(ctxt,
10186                                                                  ctxt->
10187                                                                  state));
10188                 } else {
10189                     for (j = 0; j < ctxt->states->nbState; j++) {
10190                         xmlRelaxNGAddStates(ctxt, res,
10191                             xmlRelaxNGCopyValidState(ctxt,
10192                                             ctxt->states->tabState[j]));
10193                     }
10194                 }
10195                 oldflags = ctxt->flags;
10196                 ctxt->flags |= FLAGS_IGNORABLE;
10197                 do {
10198                     progress = 0;
10199                     base = res->nbState;
10200 
10201                     if (ctxt->states != NULL) {
10202                         states = ctxt->states;
10203                         for (i = 0; i < states->nbState; i++) {
10204                             ctxt->state = states->tabState[i];
10205                             ctxt->states = NULL;
10206                             ret = xmlRelaxNGValidateDefinitionList(ctxt,
10207                                                                    define->
10208                                                                    content);
10209                             if (ret == 0) {
10210                                 if (ctxt->state != NULL) {
10211                                     tmp = xmlRelaxNGAddStates(ctxt, res,
10212                                                               ctxt->state);
10213                                     ctxt->state = NULL;
10214                                     if (tmp == 1)
10215                                         progress = 1;
10216                                 } else if (ctxt->states != NULL) {
10217                                     for (j = 0; j < ctxt->states->nbState;
10218                                          j++) {
10219                                         tmp =
10220                                             xmlRelaxNGAddStates(ctxt, res,
10221                                                    ctxt->states->tabState[j]);
10222                                         if (tmp == 1)
10223                                             progress = 1;
10224                                     }
10225                                     xmlRelaxNGFreeStates(ctxt,
10226                                                          ctxt->states);
10227                                     ctxt->states = NULL;
10228                                 }
10229                             } else {
10230                                 if (ctxt->state != NULL) {
10231                                     xmlRelaxNGFreeValidState(ctxt,
10232                                                              ctxt->state);
10233                                     ctxt->state = NULL;
10234                                 }
10235                             }
10236                         }
10237                     } else {
10238                         ret = xmlRelaxNGValidateDefinitionList(ctxt,
10239                                                                define->
10240                                                                content);
10241                         if (ret != 0) {
10242                             xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10243                             ctxt->state = NULL;
10244                         } else {
10245                             base = res->nbState;
10246                             if (ctxt->state != NULL) {
10247                                 tmp = xmlRelaxNGAddStates(ctxt, res,
10248                                                           ctxt->state);
10249                                 ctxt->state = NULL;
10250                                 if (tmp == 1)
10251                                     progress = 1;
10252                             } else if (ctxt->states != NULL) {
10253                                 for (j = 0; j < ctxt->states->nbState; j++) {
10254                                     tmp = xmlRelaxNGAddStates(ctxt, res,
10255                                                ctxt->states->tabState[j]);
10256                                     if (tmp == 1)
10257                                         progress = 1;
10258                                 }
10259                                 if (states == NULL) {
10260                                     states = ctxt->states;
10261                                 } else {
10262                                     xmlRelaxNGFreeStates(ctxt,
10263                                                          ctxt->states);
10264                                 }
10265                                 ctxt->states = NULL;
10266                             }
10267                         }
10268                     }
10269                     if (progress) {
10270                         /*
10271                          * Collect all the new nodes added at that step
10272                          * and make them the new node set
10273                          */
10274                         if (res->nbState - base == 1) {
10275                             ctxt->state = xmlRelaxNGCopyValidState(ctxt,
10276                                                                    res->
10277                                                                    tabState
10278                                                                    [base]);
10279                         } else {
10280                             if (states == NULL) {
10281                                 xmlRelaxNGNewStates(ctxt,
10282                                                     res->nbState - base);
10283                     states = ctxt->states;
10284                 if (states == NULL) {
10285                     progress = 0;
10286                     break;
10287                 }
10288                             }
10289                             states->nbState = 0;
10290                             for (i = base; i < res->nbState; i++)
10291                                 xmlRelaxNGAddStates(ctxt, states,
10292                                                     xmlRelaxNGCopyValidState
10293                                                     (ctxt, res->tabState[i]));
10294                             ctxt->states = states;
10295                         }
10296                     }
10297                 } while (progress == 1);
10298                 if (states != NULL) {
10299                     xmlRelaxNGFreeStates(ctxt, states);
10300                 }
10301                 ctxt->states = res;
10302                 ctxt->flags = oldflags;
10303 #if 0
10304                 /*
10305                  * errors may have to be propagated back...
10306                  */
10307                 if (ctxt->errNr > errNr)
10308                     xmlRelaxNGPopErrors(ctxt, errNr);
10309 #endif
10310                 ret = 0;
10311                 break;
10312             }
10313         case XML_RELAXNG_CHOICE:{
10314                 xmlRelaxNGDefinePtr list = NULL;
10315                 xmlRelaxNGStatesPtr states = NULL;
10316 
10317                 node = xmlRelaxNGSkipIgnored(ctxt, node);
10318 
10319                 errNr = ctxt->errNr;
10320                 if ((define->dflags & IS_TRIABLE) && (define->data != NULL) &&
10321             (node != NULL)) {
10322             /*
10323              * node == NULL can't be optimized since IS_TRIABLE
10324              * doesn't account for choice which may lead to
10325              * only attributes.
10326              */
10327                     xmlHashTablePtr triage =
10328                         (xmlHashTablePtr) define->data;
10329 
10330                     /*
10331                      * Something we can optimize cleanly there is only one
10332                      * possble branch out !
10333                      */
10334                     if ((node->type == XML_TEXT_NODE) ||
10335                         (node->type == XML_CDATA_SECTION_NODE)) {
10336                         list =
10337                             xmlHashLookup2(triage, BAD_CAST "#text", NULL);
10338                     } else if (node->type == XML_ELEMENT_NODE) {
10339                         if (node->ns != NULL) {
10340                             list = xmlHashLookup2(triage, node->name,
10341                                                   node->ns->href);
10342                             if (list == NULL)
10343                                 list =
10344                                     xmlHashLookup2(triage, BAD_CAST "#any",
10345                                                    node->ns->href);
10346                         } else
10347                             list =
10348                                 xmlHashLookup2(triage, node->name, NULL);
10349                         if (list == NULL)
10350                             list =
10351                                 xmlHashLookup2(triage, BAD_CAST "#any",
10352                                                NULL);
10353                     }
10354                     if (list == NULL) {
10355                         ret = -1;
10356             VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, node->name);
10357                         break;
10358                     }
10359                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
10360                     if (ret == 0) {
10361                     }
10362                     break;
10363                 }
10364 
10365                 list = define->content;
10366                 oldflags = ctxt->flags;
10367                 ctxt->flags |= FLAGS_IGNORABLE;
10368 
10369                 while (list != NULL) {
10370                     oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
10371                     ret = xmlRelaxNGValidateDefinition(ctxt, list);
10372                     if (ret == 0) {
10373                         if (states == NULL) {
10374                             states = xmlRelaxNGNewStates(ctxt, 1);
10375                         }
10376                         if (ctxt->state != NULL) {
10377                             xmlRelaxNGAddStates(ctxt, states, ctxt->state);
10378                         } else if (ctxt->states != NULL) {
10379                             for (i = 0; i < ctxt->states->nbState; i++) {
10380                                 xmlRelaxNGAddStates(ctxt, states,
10381                                                     ctxt->states->
10382                                                     tabState[i]);
10383                             }
10384                             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10385                             ctxt->states = NULL;
10386                         }
10387                     } else {
10388                         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10389                     }
10390                     ctxt->state = oldstate;
10391                     list = list->next;
10392                 }
10393                 if (states != NULL) {
10394                     xmlRelaxNGFreeValidState(ctxt, oldstate);
10395                     ctxt->states = states;
10396                     ctxt->state = NULL;
10397                     ret = 0;
10398                 } else {
10399                     ctxt->states = NULL;
10400                 }
10401                 ctxt->flags = oldflags;
10402                 if (ret != 0) {
10403                     if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
10404                         xmlRelaxNGDumpValidError(ctxt);
10405                     }
10406                 } else {
10407                     if (ctxt->errNr > errNr)
10408                         xmlRelaxNGPopErrors(ctxt, errNr);
10409                 }
10410                 break;
10411             }
10412         case XML_RELAXNG_DEF:
10413         case XML_RELAXNG_GROUP:
10414             ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
10415             break;
10416         case XML_RELAXNG_INTERLEAVE:
10417             ret = xmlRelaxNGValidateInterleave(ctxt, define);
10418             break;
10419         case XML_RELAXNG_ATTRIBUTE:
10420             ret = xmlRelaxNGValidateAttribute(ctxt, define);
10421             break;
10422         case XML_RELAXNG_START:
10423         case XML_RELAXNG_NOOP:
10424         case XML_RELAXNG_REF:
10425         case XML_RELAXNG_EXTERNALREF:
10426         case XML_RELAXNG_PARENTREF:
10427             ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
10428             break;
10429         case XML_RELAXNG_DATATYPE:{
10430                 xmlNodePtr child;
10431                 xmlChar *content = NULL;
10432 
10433                 child = node;
10434                 while (child != NULL) {
10435                     if (child->type == XML_ELEMENT_NODE) {
10436                         VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
10437                                    node->parent->name);
10438                         ret = -1;
10439                         break;
10440                     } else if ((child->type == XML_TEXT_NODE) ||
10441                                (child->type == XML_CDATA_SECTION_NODE)) {
10442                         content = xmlStrcat(content, child->content);
10443                     }
10444                     /* TODO: handle entities ... */
10445                     child = child->next;
10446                 }
10447                 if (ret == -1) {
10448                     if (content != NULL)
10449                         xmlFree(content);
10450                     break;
10451                 }
10452                 if (content == NULL) {
10453                     content = xmlStrdup(BAD_CAST "");
10454                     if (content == NULL) {
10455                         xmlRngVErrMemory(ctxt, "validating\n");
10456                         ret = -1;
10457                         break;
10458                     }
10459                 }
10460                 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
10461                                                  ctxt->state->seq);
10462                 if (ret == -1) {
10463                     VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
10464                 } else if (ret == 0) {
10465                     ctxt->state->seq = NULL;
10466                 }
10467                 if (content != NULL)
10468                     xmlFree(content);
10469                 break;
10470             }
10471         case XML_RELAXNG_VALUE:{
10472                 xmlChar *content = NULL;
10473                 xmlChar *oldvalue;
10474                 xmlNodePtr child;
10475 
10476                 child = node;
10477                 while (child != NULL) {
10478                     if (child->type == XML_ELEMENT_NODE) {
10479                         VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
10480                                    node->parent->name);
10481                         ret = -1;
10482                         break;
10483                     } else if ((child->type == XML_TEXT_NODE) ||
10484                                (child->type == XML_CDATA_SECTION_NODE)) {
10485                         content = xmlStrcat(content, child->content);
10486                     }
10487                     /* TODO: handle entities ... */
10488                     child = child->next;
10489                 }
10490                 if (ret == -1) {
10491                     if (content != NULL)
10492                         xmlFree(content);
10493                     break;
10494                 }
10495                 if (content == NULL) {
10496                     content = xmlStrdup(BAD_CAST "");
10497                     if (content == NULL) {
10498                         xmlRngVErrMemory(ctxt, "validating\n");
10499                         ret = -1;
10500                         break;
10501                     }
10502                 }
10503                 oldvalue = ctxt->state->value;
10504                 ctxt->state->value = content;
10505                 ret = xmlRelaxNGValidateValue(ctxt, define);
10506                 ctxt->state->value = oldvalue;
10507                 if (ret == -1) {
10508                     VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
10509                 } else if (ret == 0) {
10510                     ctxt->state->seq = NULL;
10511                 }
10512                 if (content != NULL)
10513                     xmlFree(content);
10514                 break;
10515             }
10516         case XML_RELAXNG_LIST:{
10517                 xmlChar *content;
10518                 xmlNodePtr child;
10519                 xmlChar *oldvalue, *oldendvalue;
10520                 int len;
10521 
10522                 /*
10523                  * Make sure it's only text nodes
10524                  */
10525 
10526                 content = NULL;
10527                 child = node;
10528                 while (child != NULL) {
10529                     if (child->type == XML_ELEMENT_NODE) {
10530                         VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
10531                                    node->parent->name);
10532                         ret = -1;
10533                         break;
10534                     } else if ((child->type == XML_TEXT_NODE) ||
10535                                (child->type == XML_CDATA_SECTION_NODE)) {
10536                         content = xmlStrcat(content, child->content);
10537                     }
10538                     /* TODO: handle entities ... */
10539                     child = child->next;
10540                 }
10541                 if (ret == -1) {
10542                     if (content != NULL)
10543                         xmlFree(content);
10544                     break;
10545                 }
10546                 if (content == NULL) {
10547                     content = xmlStrdup(BAD_CAST "");
10548                     if (content == NULL) {
10549                         xmlRngVErrMemory(ctxt, "validating\n");
10550                         ret = -1;
10551                         break;
10552                     }
10553                 }
10554                 len = xmlStrlen(content);
10555                 oldvalue = ctxt->state->value;
10556                 oldendvalue = ctxt->state->endvalue;
10557                 ctxt->state->value = content;
10558                 ctxt->state->endvalue = content + len;
10559                 ret = xmlRelaxNGValidateValue(ctxt, define);
10560                 ctxt->state->value = oldvalue;
10561                 ctxt->state->endvalue = oldendvalue;
10562                 if (ret == -1) {
10563                     VALID_ERR(XML_RELAXNG_ERR_LIST);
10564                 } else if ((ret == 0) && (node != NULL)) {
10565                     ctxt->state->seq = node->next;
10566                 }
10567                 if (content != NULL)
10568                     xmlFree(content);
10569                 break;
10570             }
10571         case XML_RELAXNG_EXCEPT:
10572         case XML_RELAXNG_PARAM:
10573             TODO ret = -1;
10574             break;
10575     }
10576     ctxt->depth--;
10577 #ifdef DEBUG
10578     for (i = 0; i < ctxt->depth; i++)
10579         xmlGenericError(xmlGenericErrorContext, " ");
10580     xmlGenericError(xmlGenericErrorContext,
10581                     "Validating %s ", xmlRelaxNGDefName(define));
10582     if (define->name != NULL)
10583         xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
10584     if (ret == 0)
10585         xmlGenericError(xmlGenericErrorContext, "suceeded\n");
10586     else
10587         xmlGenericError(xmlGenericErrorContext, "failed\n");
10588 #endif
10589     return (ret);
10590 }
10591 
10592 /**
10593  * xmlRelaxNGValidateDefinition:
10594  * @ctxt:  a Relax-NG validation context
10595  * @define:  the definition to verify
10596  *
10597  * Validate the current node lists against the definition
10598  *
10599  * Returns 0 if the validation succeeded or an error code.
10600  */
10601 static int
10602 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
10603                              xmlRelaxNGDefinePtr define)
10604 {
10605     xmlRelaxNGStatesPtr states, res;
10606     int i, j, k, ret, oldflags;
10607 
10608     /*
10609      * We should NOT have both ctxt->state and ctxt->states
10610      */
10611     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10612         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10613         ctxt->state = NULL;
10614     }
10615 
10616     if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
10617         if (ctxt->states != NULL) {
10618             ctxt->state = ctxt->states->tabState[0];
10619             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10620             ctxt->states = NULL;
10621         }
10622         ret = xmlRelaxNGValidateState(ctxt, define);
10623         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10624             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10625             ctxt->state = NULL;
10626         }
10627         if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10628             ctxt->state = ctxt->states->tabState[0];
10629             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10630             ctxt->states = NULL;
10631         }
10632         return (ret);
10633     }
10634 
10635     states = ctxt->states;
10636     ctxt->states = NULL;
10637     res = NULL;
10638     j = 0;
10639     oldflags = ctxt->flags;
10640     ctxt->flags |= FLAGS_IGNORABLE;
10641     for (i = 0; i < states->nbState; i++) {
10642         ctxt->state = states->tabState[i];
10643         ctxt->states = NULL;
10644         ret = xmlRelaxNGValidateState(ctxt, define);
10645         /*
10646          * We should NOT have both ctxt->state and ctxt->states
10647          */
10648         if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10649             TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10650             ctxt->state = NULL;
10651         }
10652         if (ret == 0) {
10653             if (ctxt->states == NULL) {
10654                 if (res != NULL) {
10655                     /* add the state to the container */
10656                     xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10657                     ctxt->state = NULL;
10658                 } else {
10659                     /* add the state directly in states */
10660                     states->tabState[j++] = ctxt->state;
10661                     ctxt->state = NULL;
10662                 }
10663             } else {
10664                 if (res == NULL) {
10665                     /* make it the new container and copy other results */
10666                     res = ctxt->states;
10667                     ctxt->states = NULL;
10668                     for (k = 0; k < j; k++)
10669                         xmlRelaxNGAddStates(ctxt, res,
10670                                             states->tabState[k]);
10671                 } else {
10672                     /* add all the new results to res and reff the container */
10673                     for (k = 0; k < ctxt->states->nbState; k++)
10674                         xmlRelaxNGAddStates(ctxt, res,
10675                                             ctxt->states->tabState[k]);
10676                     xmlRelaxNGFreeStates(ctxt, ctxt->states);
10677                     ctxt->states = NULL;
10678                 }
10679             }
10680         } else {
10681             if (ctxt->state != NULL) {
10682                 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10683                 ctxt->state = NULL;
10684             } else if (ctxt->states != NULL) {
10685                 for (k = 0; k < ctxt->states->nbState; k++)
10686                     xmlRelaxNGFreeValidState(ctxt,
10687                                              ctxt->states->tabState[k]);
10688                 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10689                 ctxt->states = NULL;
10690             }
10691         }
10692     }
10693     ctxt->flags = oldflags;
10694     if (res != NULL) {
10695         xmlRelaxNGFreeStates(ctxt, states);
10696         ctxt->states = res;
10697         ret = 0;
10698     } else if (j > 1) {
10699         states->nbState = j;
10700         ctxt->states = states;
10701         ret = 0;
10702     } else if (j == 1) {
10703         ctxt->state = states->tabState[0];
10704         xmlRelaxNGFreeStates(ctxt, states);
10705         ret = 0;
10706     } else {
10707         ret = -1;
10708         xmlRelaxNGFreeStates(ctxt, states);
10709         if (ctxt->states != NULL) {
10710             xmlRelaxNGFreeStates(ctxt, ctxt->states);
10711             ctxt->states = NULL;
10712         }
10713     }
10714     if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10715         TODO xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10716         ctxt->state = NULL;
10717     }
10718     return (ret);
10719 }
10720 
10721 /**
10722  * xmlRelaxNGValidateDocument:
10723  * @ctxt:  a Relax-NG validation context
10724  * @doc:  the document
10725  *
10726  * Validate the given document
10727  *
10728  * Returns 0 if the validation succeeded or an error code.
10729  */
10730 static int
10731 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
10732 {
10733     int ret;
10734     xmlRelaxNGPtr schema;
10735     xmlRelaxNGGrammarPtr grammar;
10736     xmlRelaxNGValidStatePtr state;
10737     xmlNodePtr node;
10738 
10739     if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10740         return (-1);
10741 
10742     ctxt->errNo = XML_RELAXNG_OK;
10743     schema = ctxt->schema;
10744     grammar = schema->topgrammar;
10745     if (grammar == NULL) {
10746         VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
10747         return (-1);
10748     }
10749     state = xmlRelaxNGNewValidState(ctxt, NULL);
10750     ctxt->state = state;
10751     ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
10752     if ((ctxt->state != NULL) && (state->seq != NULL)) {
10753         state = ctxt->state;
10754         node = state->seq;
10755         node = xmlRelaxNGSkipIgnored(ctxt, node);
10756         if (node != NULL) {
10757             if (ret != -1) {
10758                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10759                 ret = -1;
10760             }
10761         }
10762     } else if (ctxt->states != NULL) {
10763         int i;
10764         int tmp = -1;
10765 
10766         for (i = 0; i < ctxt->states->nbState; i++) {
10767             state = ctxt->states->tabState[i];
10768             node = state->seq;
10769             node = xmlRelaxNGSkipIgnored(ctxt, node);
10770             if (node == NULL)
10771                 tmp = 0;
10772             xmlRelaxNGFreeValidState(ctxt, state);
10773         }
10774         if (tmp == -1) {
10775             if (ret != -1) {
10776                 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10777                 ret = -1;
10778             }
10779         }
10780     }
10781     if (ctxt->state != NULL) {
10782         xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10783         ctxt->state = NULL;
10784     }
10785     if (ret != 0)
10786         xmlRelaxNGDumpValidError(ctxt);
10787 #ifdef DEBUG
10788     else if (ctxt->errNr != 0) {
10789         ctxt->error(ctxt->userData,
10790                     "%d Extra error messages left on stack !\n",
10791                     ctxt->errNr);
10792         xmlRelaxNGDumpValidError(ctxt);
10793     }
10794 #endif
10795 #ifdef LIBXML_VALID_ENABLED
10796     if (ctxt->idref == 1) {
10797         xmlValidCtxt vctxt;
10798 
10799         memset(&vctxt, 0, sizeof(xmlValidCtxt));
10800         vctxt.valid = 1;
10801         vctxt.error = ctxt->error;
10802         vctxt.warning = ctxt->warning;
10803         vctxt.userData = ctxt->userData;
10804 
10805         if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10806             ret = -1;
10807     }
10808 #endif /* LIBXML_VALID_ENABLED */
10809     if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10810         ret = -1;
10811 
10812     return (ret);
10813 }
10814 
10815 /**
10816  * xmlRelaxNGCleanPSVI:
10817  * @node:  an input element or document
10818  *
10819  * Call this routine to speed up XPath computation on static documents.
10820  * This stamps all the element nodes with the document order
10821  * Like for line information, the order is kept in the element->content
10822  * field, the value stored is actually - the node number (starting at -1)
10823  * to be able to differentiate from line numbers.
10824  *
10825  * Returns the number of elements found in the document or -1 in case
10826  *    of error.
10827  */
10828 static void
10829 xmlRelaxNGCleanPSVI(xmlNodePtr node) {
10830     xmlNodePtr cur;
10831 
10832     if ((node == NULL) ||
10833         ((node->type != XML_ELEMENT_NODE) &&
10834          (node->type != XML_DOCUMENT_NODE) &&
10835          (node->type != XML_HTML_DOCUMENT_NODE)))
10836     return;
10837     if (node->type == XML_ELEMENT_NODE)
10838         node->psvi = NULL;
10839 
10840     cur = node->children;
10841     while (cur != NULL) {
10842     if (cur->type == XML_ELEMENT_NODE) {
10843         cur->psvi = NULL;
10844         if (cur->children != NULL) {
10845         cur = cur->children;
10846         continue;
10847         }
10848     }
10849     if (cur->next != NULL) {
10850         cur = cur->next;
10851         continue;
10852     }
10853     do {
10854         cur = cur->parent;
10855         if (cur == NULL)
10856         break;
10857         if (cur == node) {
10858         cur = NULL;
10859         break;
10860         }
10861         if (cur->next != NULL) {
10862         cur = cur->next;
10863         break;
10864         }
10865     } while (cur != NULL);
10866     }
10867     return;
10868 }
10869 /************************************************************************
10870  *                                  *
10871  *          Validation interfaces               *
10872  *                                  *
10873  ************************************************************************/
10874 
10875 /**
10876  * xmlRelaxNGNewValidCtxt:
10877  * @schema:  a precompiled XML RelaxNGs
10878  *
10879  * Create an XML RelaxNGs validation context based on the given schema
10880  *
10881  * Returns the validation context or NULL in case of error
10882  */
10883 xmlRelaxNGValidCtxtPtr
10884 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema)
10885 {
10886     xmlRelaxNGValidCtxtPtr ret;
10887 
10888     ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10889     if (ret == NULL) {
10890         xmlRngVErrMemory(NULL, "building context\n");
10891         return (NULL);
10892     }
10893     memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10894     ret->schema = schema;
10895     ret->error = xmlGenericError;
10896     ret->userData = xmlGenericErrorContext;
10897     ret->errNr = 0;
10898     ret->errMax = 0;
10899     ret->err = NULL;
10900     ret->errTab = NULL;
10901     if (schema != NULL)
10902     ret->idref = schema->idref;
10903     ret->states = NULL;
10904     ret->freeState = NULL;
10905     ret->freeStates = NULL;
10906     ret->errNo = XML_RELAXNG_OK;
10907     return (ret);
10908 }
10909 
10910 /**
10911  * xmlRelaxNGFreeValidCtxt:
10912  * @ctxt:  the schema validation context
10913  *
10914  * Free the resources associated to the schema validation context
10915  */
10916 void
10917 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt)
10918 {
10919     int k;
10920 
10921     if (ctxt == NULL)
10922         return;
10923     if (ctxt->states != NULL)
10924         xmlRelaxNGFreeStates(NULL, ctxt->states);
10925     if (ctxt->freeState != NULL) {
10926         for (k = 0; k < ctxt->freeState->nbState; k++) {
10927             xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10928         }
10929         xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10930     }
10931     if (ctxt->freeStates != NULL) {
10932         for (k = 0; k < ctxt->freeStatesNr; k++) {
10933             xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10934         }
10935         xmlFree(ctxt->freeStates);
10936     }
10937     if (ctxt->errTab != NULL)
10938         xmlFree(ctxt->errTab);
10939     if (ctxt->elemTab != NULL) {
10940         xmlRegExecCtxtPtr exec;
10941 
10942         exec = xmlRelaxNGElemPop(ctxt);
10943         while (exec != NULL) {
10944             xmlRegFreeExecCtxt(exec);
10945             exec = xmlRelaxNGElemPop(ctxt);
10946         }
10947         xmlFree(ctxt->elemTab);
10948     }
10949     xmlFree(ctxt);
10950 }
10951 
10952 /**
10953  * xmlRelaxNGSetValidErrors:
10954  * @ctxt:  a Relax-NG validation context
10955  * @err:  the error function
10956  * @warn: the warning function
10957  * @ctx: the functions context
10958  *
10959  * Set the error and warning callback informations
10960  */
10961 void
10962 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10963                          xmlRelaxNGValidityErrorFunc err,
10964                          xmlRelaxNGValidityWarningFunc warn, void *ctx)
10965 {
10966     if (ctxt == NULL)
10967         return;
10968     ctxt->error = err;
10969     ctxt->warning = warn;
10970     ctxt->userData = ctx;
10971     ctxt->serror = NULL;
10972 }
10973 
10974 /**
10975  * xmlRelaxNGSetValidStructuredErrors:
10976  * @ctxt:  a Relax-NG validation context
10977  * @serror:  the structured error function
10978  * @ctx: the functions context
10979  *
10980  * Set the structured error callback
10981  */
10982 void
10983 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt,
10984                                    xmlStructuredErrorFunc serror, void *ctx)
10985 {
10986     if (ctxt == NULL)
10987         return;
10988     ctxt->serror = serror;
10989     ctxt->error = NULL;
10990     ctxt->warning = NULL;
10991     ctxt->userData = ctx;
10992 }
10993 
10994 /**
10995  * xmlRelaxNGGetValidErrors:
10996  * @ctxt:  a Relax-NG validation context
10997  * @err:  the error function result
10998  * @warn: the warning function result
10999  * @ctx: the functions context result
11000  *
11001  * Get the error and warning callback informations
11002  *
11003  * Returns -1 in case of error and 0 otherwise
11004  */
11005 int
11006 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
11007                          xmlRelaxNGValidityErrorFunc * err,
11008                          xmlRelaxNGValidityWarningFunc * warn, void **ctx)
11009 {
11010     if (ctxt == NULL)
11011         return (-1);
11012     if (err != NULL)
11013         *err = ctxt->error;
11014     if (warn != NULL)
11015         *warn = ctxt->warning;
11016     if (ctx != NULL)
11017         *ctx = ctxt->userData;
11018     return (0);
11019 }
11020 
11021 /**
11022  * xmlRelaxNGValidateDoc:
11023  * @ctxt:  a Relax-NG validation context
11024  * @doc:  a parsed document tree
11025  *
11026  * Validate a document tree in memory.
11027  *
11028  * Returns 0 if the document is valid, a positive error code
11029  *     number otherwise and -1 in case of internal or API error.
11030  */
11031 int
11032 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
11033 {
11034     int ret;
11035 
11036     if ((ctxt == NULL) || (doc == NULL))
11037         return (-1);
11038 
11039     ctxt->doc = doc;
11040 
11041     ret = xmlRelaxNGValidateDocument(ctxt, doc);
11042     /*
11043      * Remove all left PSVI
11044      */
11045     xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
11046 
11047     /*
11048      * TODO: build error codes
11049      */
11050     if (ret == -1)
11051         return (1);
11052     return (ret);
11053 }
11054 
11055 #define bottom_relaxng
11056 #include "elfgcchack.h"
11057 #endif /* LIBXML_SCHEMAS_ENABLED */
11058