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