| Index: third_party/libxml/relaxng.c
|
| diff --git a/third_party/libxml/relaxng.c b/third_party/libxml/relaxng.c
|
| index 60fdbab9256dcd9dbe5d101c31713fed163ecffa..6dbc499fccbcd59c46020c0cbabeee652747a8ae 100644
|
| --- a/third_party/libxml/relaxng.c
|
| +++ b/third_party/libxml/relaxng.c
|
| @@ -149,6 +149,7 @@ typedef enum {
|
| #define IS_PROCESSED (1 << 5)
|
| #define IS_COMPILABLE (1 << 6)
|
| #define IS_NOT_COMPILABLE (1 << 7)
|
| +#define IS_EXTERNAL_REF (1 << 8)
|
|
|
| struct _xmlRelaxNGDefine {
|
| xmlRelaxNGType type; /* the type of definition */
|
| @@ -414,6 +415,7 @@ struct _xmlRelaxNGDocument {
|
| xmlDocPtr doc; /* the associated XML document */
|
| xmlRelaxNGDefinePtr content; /* the definitions */
|
| xmlRelaxNGPtr schema; /* the schema */
|
| + int externalRef; /* 1 if an external ref */
|
| };
|
|
|
|
|
| @@ -1006,7 +1008,7 @@ xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
|
| xmlRelaxNGStatesPtr ret;
|
|
|
| if ((ctxt != NULL) &&
|
| - (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
|
| + (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
|
| ctxt->freeStatesNr--;
|
| ret = ctxt->freeStates[ctxt->freeStatesNr];
|
| ret->nbState = 0;
|
| @@ -1970,6 +1972,7 @@ xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt,
|
| ret->doc = doc;
|
| ret->href = xmlStrdup(URL);
|
| ret->next = ctxt->documents;
|
| + ret->externalRef = 1;
|
| ctxt->documents = ret;
|
|
|
| /*
|
| @@ -2372,6 +2375,9 @@ xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt,
|
| } else {
|
| node = seq = NULL;
|
| }
|
| + if ((node == NULL) && (seq == NULL)) {
|
| + node = ctxt->pnode;
|
| + }
|
| xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
|
| }
|
| /*
|
| @@ -2849,6 +2855,10 @@ xmlRelaxNGCleanupTypes(void)
|
| * *
|
| ************************************************************************/
|
|
|
| +/* from automata.c but not exported */
|
| +void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
|
| +
|
| +
|
| static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
|
| xmlRelaxNGDefinePtr def);
|
|
|
| @@ -3032,6 +3042,17 @@ xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
|
| ctxt->am = xmlNewAutomata();
|
| if (ctxt->am == NULL)
|
| return (-1);
|
| +
|
| + /*
|
| + * assume identical strings but not same pointer are different
|
| + * atoms, needed for non-determinism detection
|
| + * That way if 2 elements with the same name are in a choice
|
| + * branch the automata is found non-deterministic and
|
| + * we fallback to the normal validation which does the right
|
| + * thing of exploring both choices.
|
| + */
|
| + xmlAutomataSetFlags(ctxt->am, 1);
|
| +
|
| ctxt->state = xmlAutomataGetInitState(ctxt->am);
|
| while (list != NULL) {
|
| xmlRelaxNGCompile(ctxt, list);
|
| @@ -3063,6 +3084,7 @@ xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
|
| ctxt->am = xmlNewAutomata();
|
| if (ctxt->am == NULL)
|
| return (-1);
|
| + xmlAutomataSetFlags(ctxt->am, 1);
|
| ctxt->state = xmlAutomataGetInitState(ctxt->am);
|
| while (list != NULL) {
|
| xmlRelaxNGCompile(ctxt, list);
|
| @@ -3071,6 +3093,11 @@ xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
|
| xmlAutomataSetFinalState(ctxt->am, ctxt->state);
|
| def->contModel = xmlAutomataCompile(ctxt->am);
|
| if (!xmlRegexpIsDeterminist(def->contModel)) {
|
| +#ifdef DEBUG_COMPILE
|
| + xmlGenericError(xmlGenericErrorContext,
|
| + "Content model not determinist %s\n",
|
| + def->name);
|
| +#endif
|
| /*
|
| * we can only use the automata if it is determinist
|
| */
|
| @@ -3098,7 +3125,11 @@ xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def)
|
| case XML_RELAXNG_OPTIONAL:{
|
| xmlAutomataStatePtr oldstate = ctxt->state;
|
|
|
| - xmlRelaxNGCompile(ctxt, def->content);
|
| + list = def->content;
|
| + while (list != NULL) {
|
| + xmlRelaxNGCompile(ctxt, list);
|
| + list = list->next;
|
| + }
|
| xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
|
| break;
|
| }
|
| @@ -3440,6 +3471,9 @@ xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
|
| {
|
| xmlChar *ret, *escape;
|
|
|
| + if (node == NULL)
|
| + return(NULL);
|
| +
|
| if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
|
| ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
|
| if (ret != NULL) {
|
| @@ -4616,6 +4650,72 @@ xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
|
| }
|
|
|
| /**
|
| + * xmlRelaxNGParseImportRef:
|
| + * @payload: the parser context
|
| + * @data: the current grammar
|
| + * @name: the reference name
|
| + *
|
| + * Import import one references into the current grammar
|
| + */
|
| +static void
|
| +xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) {
|
| + xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
|
| + xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
|
| + int tmp;
|
| +
|
| + def->dflags |= IS_EXTERNAL_REF;
|
| +
|
| + tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
|
| + if (tmp < 0) {
|
| + xmlRelaxNGDefinePtr prev;
|
| +
|
| + prev = (xmlRelaxNGDefinePtr)
|
| + xmlHashLookup(ctxt->grammar->refs, def->name);
|
| + if (prev == NULL) {
|
| + if (def->name != NULL) {
|
| + xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
|
| + "Error refs definitions '%s'\n",
|
| + def->name, NULL);
|
| + } else {
|
| + xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
|
| + "Error refs definitions\n",
|
| + NULL, NULL);
|
| + }
|
| + } else {
|
| + def->nextHash = prev->nextHash;
|
| + prev->nextHash = def;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * xmlRelaxNGParseImportRefs:
|
| + * @ctxt: the parser context
|
| + * @grammar: the sub grammar
|
| + *
|
| + * Import references from the subgrammar into the current grammar
|
| + *
|
| + * Returns 0 in case of success, -1 in case of failure
|
| + */
|
| +static int
|
| +xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
|
| + xmlRelaxNGGrammarPtr grammar) {
|
| + if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
|
| + return(-1);
|
| + if (grammar->refs == NULL)
|
| + return(0);
|
| + if (ctxt->grammar->refs == NULL)
|
| + ctxt->grammar->refs = xmlHashCreate(10);
|
| + if (ctxt->grammar->refs == NULL) {
|
| + xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
|
| + "Could not create references hash\n", NULL, NULL);
|
| + return(-1);
|
| + }
|
| + xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
|
| + return(0);
|
| +}
|
| +
|
| +/**
|
| * xmlRelaxNGProcessExternalRef:
|
| * @ctxt: the parser context
|
| * @node: the externlRef node
|
| @@ -4683,6 +4783,8 @@ xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
|
| if ((docu->schema != NULL) &&
|
| (docu->schema->topgrammar != NULL)) {
|
| docu->content = docu->schema->topgrammar->start;
|
| + if (docu->schema->topgrammar->refs)
|
| + xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
|
| }
|
|
|
| /*
|
| @@ -5267,7 +5369,8 @@ xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
|
| } else {
|
| xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
|
| "expecting name, anyName, nsName or choice : got %s\n",
|
| - node->name, NULL);
|
| + (node == NULL ? (const xmlChar *) "nothing" : node->name),
|
| + NULL);
|
| return (NULL);
|
| }
|
| if (ret != def) {
|
| @@ -5569,6 +5672,12 @@ xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
|
| xmlRelaxNGGrammarPtr grammar;
|
| xmlRelaxNGDefinePtr def, cur;
|
|
|
| + /*
|
| + * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
|
| + */
|
| + if (ref->dflags & IS_EXTERNAL_REF)
|
| + return;
|
| +
|
| grammar = ctxt->grammar;
|
| if (grammar == NULL) {
|
| xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
|
| @@ -6133,7 +6242,7 @@ xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
|
| xmlRelaxNGDefinePtr cur, int flags,
|
| xmlRelaxNGType ptype)
|
| {
|
| - int nflags = flags;
|
| + int nflags;
|
| xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
|
|
|
| while (cur != NULL) {
|
| @@ -6157,6 +6266,16 @@ xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
|
| "Found forbidden pattern data/except//ref\n",
|
| NULL, NULL);
|
| }
|
| + if (cur->content == NULL) {
|
| + if (cur->type == XML_RELAXNG_PARENTREF)
|
| + xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
|
| + "Internal found no define for parent refs\n",
|
| + NULL, NULL);
|
| + else
|
| + xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
|
| + "Internal found no define for ref %s\n",
|
| + (cur->name ? cur->name: BAD_CAST "null"), NULL);
|
| + }
|
| if (cur->depth > -4) {
|
| cur->depth = -4;
|
| ret = xmlRelaxNGCheckRules(ctxt, cur->content,
|
| @@ -6408,6 +6527,10 @@ xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
|
| if (ptype == XML_RELAXNG_GROUP) {
|
| val = xmlRelaxNGGroupContentType(val, ret);
|
| } else if (ptype == XML_RELAXNG_INTERLEAVE) {
|
| + /*
|
| + * TODO: scan complain that tmp is never used, seems on purpose
|
| + * need double-checking
|
| + */
|
| tmp = xmlRelaxNGGroupContentType(val, ret);
|
| if (tmp != XML_RELAXNG_CONTENT_ERROR)
|
| tmp = xmlRelaxNGMaxContentType(val, ret);
|
| @@ -6495,6 +6618,9 @@ xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
|
| ctxt);
|
| }
|
|
|
| +
|
| + /* @@@@ */
|
| +
|
| ctxt->grammar = old;
|
| return (ret);
|
| }
|
| @@ -8343,7 +8469,7 @@ xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
|
| ret = -1;
|
| else
|
| ret = 1;
|
| - xmlRelaxNGFreeValidState(ctxt, state);
|
| + xmlRelaxNGFreeValidState(ctxt, ctxt->state);
|
| ctxt->state = NULL;
|
| #ifdef DEBUG_PROGRESSIVE
|
| if (ret < 0)
|
| @@ -8812,7 +8938,12 @@ xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
|
| }
|
| case XML_RELAXNG_REF:
|
| case XML_RELAXNG_PARENTREF:
|
| - ret = xmlRelaxNGValidateValue(ctxt, define->content);
|
| + if (define->content == NULL) {
|
| + VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
|
| + ret = -1;
|
| + } else {
|
| + ret = xmlRelaxNGValidateValue(ctxt, define->content);
|
| + }
|
| break;
|
| default:
|
| TODO ret = -1;
|
| @@ -9319,6 +9450,7 @@ xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
|
| oldstate =
|
| ctxt->states->tabState[ctxt->states->nbState - 1];
|
| ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
|
| + ctxt->states->nbState--;
|
| }
|
| }
|
| for (j = 0; j < ctxt->states->nbState ; j++) {
|
| @@ -9327,7 +9459,12 @@ xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
|
| xmlRelaxNGFreeStates(ctxt, ctxt->states);
|
| ctxt->states = NULL;
|
| if (found == 0) {
|
| - VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
|
| + if (cur == NULL) {
|
| + VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA,
|
| + (const xmlChar *) "noname");
|
| + } else {
|
| + VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
|
| + }
|
| ret = -1;
|
| ctxt->state = oldstate;
|
| goto done;
|
| @@ -9874,8 +10011,8 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
|
| }
|
| for (i = 0; i < ctxt->states->nbState; i++) {
|
| xmlRelaxNGFreeValidState(ctxt,
|
| - ctxt->states->
|
| - tabState[i]);
|
| + ctxt->states->tabState[i]);
|
| + ctxt->states->tabState[i] = NULL;
|
| }
|
| xmlRelaxNGFreeStates(ctxt, ctxt->states);
|
| ctxt->flags = oldflags;
|
| @@ -9997,11 +10134,8 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
|
| } else {
|
| for (j = 0; j < ctxt->states->nbState; j++) {
|
| xmlRelaxNGAddStates(ctxt, res,
|
| - xmlRelaxNGCopyValidState(ctxt,
|
| - ctxt->
|
| - states->
|
| - tabState
|
| - [j]));
|
| + xmlRelaxNGCopyValidState(ctxt,
|
| + ctxt->states->tabState[j]));
|
| }
|
| }
|
| oldflags = ctxt->flags;
|
| @@ -10030,10 +10164,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
|
| j++) {
|
| tmp =
|
| xmlRelaxNGAddStates(ctxt, res,
|
| - ctxt->
|
| - states->
|
| - tabState
|
| - [j]);
|
| + ctxt->states->tabState[j]);
|
| if (tmp == 1)
|
| progress = 1;
|
| }
|
| @@ -10067,9 +10198,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
|
| } else if (ctxt->states != NULL) {
|
| for (j = 0; j < ctxt->states->nbState; j++) {
|
| tmp = xmlRelaxNGAddStates(ctxt, res,
|
| - ctxt->
|
| - states->
|
| - tabState[j]);
|
| + ctxt->states->tabState[j]);
|
| if (tmp == 1)
|
| progress = 1;
|
| }
|
| @@ -10107,8 +10236,7 @@ xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
|
| for (i = base; i < res->nbState; i++)
|
| xmlRelaxNGAddStates(ctxt, states,
|
| xmlRelaxNGCopyValidState
|
| - (ctxt,
|
| - res->tabState[i]));
|
| + (ctxt, res->tabState[i]));
|
| ctxt->states = states;
|
| }
|
| }
|
| @@ -10630,6 +10758,60 @@ xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
|
| return (ret);
|
| }
|
|
|
| +/**
|
| + * xmlRelaxNGCleanPSVI:
|
| + * @node: an input element or document
|
| + *
|
| + * Call this routine to speed up XPath computation on static documents.
|
| + * This stamps all the element nodes with the document order
|
| + * Like for line information, the order is kept in the element->content
|
| + * field, the value stored is actually - the node number (starting at -1)
|
| + * to be able to differentiate from line numbers.
|
| + *
|
| + * Returns the number of elements found in the document or -1 in case
|
| + * of error.
|
| + */
|
| +static void
|
| +xmlRelaxNGCleanPSVI(xmlNodePtr node) {
|
| + xmlNodePtr cur;
|
| +
|
| + if ((node == NULL) ||
|
| + ((node->type != XML_ELEMENT_NODE) &&
|
| + (node->type != XML_DOCUMENT_NODE) &&
|
| + (node->type != XML_HTML_DOCUMENT_NODE)))
|
| + return;
|
| + if (node->type == XML_ELEMENT_NODE)
|
| + node->psvi = NULL;
|
| +
|
| + cur = node->children;
|
| + while (cur != NULL) {
|
| + if (cur->type == XML_ELEMENT_NODE) {
|
| + cur->psvi = NULL;
|
| + if (cur->children != NULL) {
|
| + cur = cur->children;
|
| + continue;
|
| + }
|
| + }
|
| + if (cur->next != NULL) {
|
| + cur = cur->next;
|
| + continue;
|
| + }
|
| + do {
|
| + cur = cur->parent;
|
| + if (cur == NULL)
|
| + break;
|
| + if (cur == node) {
|
| + cur = NULL;
|
| + break;
|
| + }
|
| + if (cur->next != NULL) {
|
| + cur = cur->next;
|
| + break;
|
| + }
|
| + } while (cur != NULL);
|
| + }
|
| + return;
|
| +}
|
| /************************************************************************
|
| * *
|
| * Validation interfaces *
|
| @@ -10804,6 +10986,11 @@ xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc)
|
|
|
| ret = xmlRelaxNGValidateDocument(ctxt, doc);
|
| /*
|
| + * Remove all left PSVI
|
| + */
|
| + xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
|
| +
|
| + /*
|
| * TODO: build error codes
|
| */
|
| if (ret == -1)
|
|
|