ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Thu May 24 2012 04:34:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.