summaryrefslogtreecommitdiffstats
path: root/third_party/libxml/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libxml/parser.c')
-rw-r--r--third_party/libxml/parser.c490
1 files changed, 388 insertions, 102 deletions
diff --git a/third_party/libxml/parser.c b/third_party/libxml/parser.c
index e0e47a9..d12f429 100644
--- a/third_party/libxml/parser.c
+++ b/third_party/libxml/parser.c
@@ -126,6 +126,9 @@ static xmlParserErrors
xmlParseBalancedChunkMemoryInternal(xmlParserCtxtPtr oldctxt,
const xmlChar *string, void *user_data, xmlNodePtr *lst);
+static int
+xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity);
+
/************************************************************************
* *
* Some factorized error routines *
@@ -866,6 +869,103 @@ struct _xmlDefAttrs {
};
/**
+ * xmlAttrNormalizeSpace:
+ * @src: the source string
+ * @dst: the target string
+ *
+ * Normalize the space in non CDATA attribute values:
+ * If the attribute type is not CDATA, then the XML processor MUST further
+ * process the normalized attribute value by discarding any leading and
+ * trailing space (#x20) characters, and by replacing sequences of space
+ * (#x20) characters by a single space (#x20) character.
+ * Note that the size of dst need to be at least src, and if one doesn't need
+ * to preserve dst (and it doesn't come from a dictionary or read-only) then
+ * passing src as dst is just fine.
+ *
+ * Returns a pointer to the normalized value (dst) or NULL if no conversion
+ * is needed.
+ */
+static xmlChar *
+xmlAttrNormalizeSpace(const xmlChar *src, xmlChar *dst)
+{
+ if ((src == NULL) || (dst == NULL))
+ return(NULL);
+
+ while (*src == 0x20) src++;
+ while (*src != 0) {
+ if (*src == 0x20) {
+ while (*src == 0x20) src++;
+ if (*src != 0)
+ *dst++ = 0x20;
+ } else {
+ *dst++ = *src++;
+ }
+ }
+ *dst = 0;
+ if (dst == src)
+ return(NULL);
+ return(dst);
+}
+
+/**
+ * xmlAttrNormalizeSpace2:
+ * @src: the source string
+ *
+ * Normalize the space in non CDATA attribute values, a slightly more complex
+ * front end to avoid allocation problems when running on attribute values
+ * coming from the input.
+ *
+ * Returns a pointer to the normalized value (dst) or NULL if no conversion
+ * is needed.
+ */
+static const xmlChar *
+xmlAttrNormalizeSpace2(xmlParserCtxtPtr ctxt, const xmlChar *src, int *len)
+{
+ int i;
+ int remove_head = 0;
+ int need_realloc = 0;
+ const xmlChar *cur;
+
+ if ((ctxt == NULL) || (src == NULL) || (len == NULL))
+ return(NULL);
+ i = *len;
+ if (i <= 0)
+ return(NULL);
+
+ cur = src;
+ while (*cur == 0x20) {
+ cur++;
+ remove_head++;
+ }
+ while (*cur != 0) {
+ if (*cur == 0x20) {
+ cur++;
+ if ((*cur == 0x20) || (*cur == 0)) {
+ need_realloc = 1;
+ break;
+ }
+ } else
+ cur++;
+ }
+ if (need_realloc) {
+ xmlChar *ret;
+
+ ret = xmlStrndup(src + remove_head, i - remove_head + 1);
+ if (ret == NULL) {
+ xmlErrMemory(ctxt, NULL);
+ return(NULL);
+ }
+ xmlAttrNormalizeSpace(ret, ret);
+ *len = (int) strlen((const char *)ret);
+ return(ret);
+ } else if (remove_head) {
+ *len -= remove_head;
+ return(src + remove_head);
+ }
+ return(NULL);
+}
+
+/**
* xmlAddDefAttrs:
* @ctxt: an XML parser context
* @fullname: the element fullname
@@ -884,6 +984,14 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt,
const xmlChar *name;
const xmlChar *prefix;
+ /*
+ * Allows to detect attribute redefinitions
+ */
+ if (ctxt->attsSpecial != NULL) {
+ if (xmlHashLookup2(ctxt->attsSpecial, fullname, fullattr) != NULL)
+ return;
+ }
+
if (ctxt->attsDefault == NULL) {
ctxt->attsDefault = xmlHashCreateDict(10, ctxt->dict);
if (ctxt->attsDefault == NULL)
@@ -914,7 +1022,11 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt,
goto mem_error;
defaults->nbAttrs = 0;
defaults->maxAttrs = 4;
- xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL);
+ if (xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix,
+ defaults, NULL) < 0) {
+ xmlFree(defaults);
+ goto mem_error;
+ }
} else if (defaults->nbAttrs >= defaults->maxAttrs) {
xmlDefAttrsPtr temp;
@@ -924,7 +1036,11 @@ xmlAddDefAttrs(xmlParserCtxtPtr ctxt,
goto mem_error;
defaults = temp;
defaults->maxAttrs *= 2;
- xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix, defaults, NULL);
+ if (xmlHashUpdateEntry2(ctxt->attsDefault, name, prefix,
+ defaults, NULL) < 0) {
+ xmlFree(defaults);
+ goto mem_error;
+ }
}
/*
@@ -1147,15 +1263,16 @@ nsPush(xmlParserCtxtPtr ctxt, const xmlChar *prefix, const xmlChar *URL)
return (-1);
}
} else if (ctxt->nsNr >= ctxt->nsMax) {
+ const xmlChar ** tmp;
ctxt->nsMax *= 2;
- ctxt->nsTab = (const xmlChar **)
- xmlRealloc((char *) ctxt->nsTab,
- ctxt->nsMax * sizeof(ctxt->nsTab[0]));
- if (ctxt->nsTab == NULL) {
+ tmp = (const xmlChar **) xmlRealloc((char *) ctxt->nsTab,
+ ctxt->nsMax * sizeof(ctxt->nsTab[0]));
+ if (tmp == NULL) {
xmlErrMemory(ctxt, NULL);
ctxt->nsMax /= 2;
return (-1);
}
+ ctxt->nsTab = tmp;
}
ctxt->nsTab[ctxt->nsNr++] = prefix;
ctxt->nsTab[ctxt->nsNr++] = URL;
@@ -1476,13 +1593,16 @@ namePop(xmlParserCtxtPtr ctxt)
static int spacePush(xmlParserCtxtPtr ctxt, int val) {
if (ctxt->spaceNr >= ctxt->spaceMax) {
+ int *tmp;
+
ctxt->spaceMax *= 2;
- ctxt->spaceTab = (int *) xmlRealloc(ctxt->spaceTab,
- ctxt->spaceMax * sizeof(ctxt->spaceTab[0]));
- if (ctxt->spaceTab == NULL) {
+ tmp = (int *) xmlRealloc(ctxt->spaceTab,
+ ctxt->spaceMax * sizeof(ctxt->spaceTab[0]));
+ if (tmp == NULL) {
xmlErrMemory(ctxt, NULL);
return(0);
}
+ ctxt->spaceTab = tmp;
}
ctxt->spaceTab[ctxt->spaceNr] = val;
ctxt->space = &ctxt->spaceTab[ctxt->spaceNr];
@@ -1972,6 +2092,7 @@ xmlNewBlanksWrapperInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
buffer = xmlMallocAtomic(length);
if (buffer == NULL) {
xmlErrMemory(ctxt, NULL);
+ xmlFree(input);
return(NULL);
}
buffer [0] = ' ';
@@ -2188,7 +2309,7 @@ xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
xmlChar *tmp; \
buffer##_size *= 2; \
tmp = (xmlChar *) \
- xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \
+ xmlRealloc(buffer, buffer##_size * sizeof(xmlChar)); \
if (tmp == NULL) goto mem_error; \
buffer = tmp; \
}
@@ -2219,6 +2340,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
int buffer_size = 0;
xmlChar *current = NULL;
+ xmlChar *rep = NULL;
const xmlChar *last;
xmlEntityPtr ent;
int c,l;
@@ -2278,8 +2400,6 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
"predefined entity has no content\n");
}
} else if ((ent != NULL) && (ent->content != NULL)) {
- xmlChar *rep;
-
ctxt->depth++;
rep = xmlStringDecodeEntities(ctxt, ent->content, what,
0, 0, 0);
@@ -2294,6 +2414,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
}
}
xmlFree(rep);
+ rep = NULL;
}
} else if (ent != NULL) {
int i = xmlStrlen(ent->name);
@@ -2313,8 +2434,10 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
"String decoding PE Reference: %.30s\n", str);
ent = xmlParseStringPEReference(ctxt, &str);
if (ent != NULL) {
- xmlChar *rep;
-
+ if (ent->content == NULL) {
+ if (xmlLoadEntityContent(ctxt, ent) < 0) {
+ }
+ }
ctxt->depth++;
rep = xmlStringDecodeEntities(ctxt, ent->content, what,
0, 0, 0);
@@ -2329,6 +2452,7 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
}
}
xmlFree(rep);
+ rep = NULL;
}
}
} else {
@@ -2348,6 +2472,10 @@ xmlStringLenDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
mem_error:
xmlErrMemory(ctxt, NULL);
+ if (rep != NULL)
+ xmlFree(rep);
+ if (buffer != NULL)
+ xmlFree(buffer);
return(NULL);
}
@@ -2462,7 +2590,7 @@ static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len,
* xmlSplitQName:
* @ctxt: an XML parser context
* @name: an XML parser context
- * @prefix: a xmlChar **
+ * @prefix: a xmlChar **
*
* parse an UTF8 encoded XML qualified name string
*
@@ -2513,7 +2641,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
* for the processing speed.
*/
max = len * 2;
-
+
buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
if (buffer == NULL) {
xmlErrMemory(ctxt, NULL);
@@ -2528,7 +2656,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
tmp = (xmlChar *) xmlRealloc(buffer,
max * sizeof(xmlChar));
if (tmp == NULL) {
- xmlFree(tmp);
+ xmlFree(buffer);
xmlErrMemory(ctxt, NULL);
return(NULL);
}
@@ -2539,7 +2667,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
}
buffer[len] = 0;
}
-
+
if ((c == ':') && (*cur == 0)) {
if (buffer != NULL)
xmlFree(buffer);
@@ -2592,7 +2720,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
* for the processing speed.
*/
max = len * 2;
-
+
buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
if (buffer == NULL) {
xmlErrMemory(ctxt, NULL);
@@ -2618,7 +2746,7 @@ xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
}
buffer[len] = 0;
}
-
+
if (buffer == NULL)
ret = xmlStrndup(buf, len);
else {
@@ -3091,6 +3219,7 @@ static xmlChar *
xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
xmlChar limit = 0;
xmlChar *buf = NULL;
+ xmlChar *rep = NULL;
int len = 0;
int buf_size = 0;
int c, l, in_space = 0;
@@ -3109,7 +3238,7 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
xmlFatalErr(ctxt, XML_ERR_ATTRIBUTE_NOT_STARTED, NULL);
return(NULL);
}
-
+
/*
* allocate a translation buffer.
*/
@@ -3149,7 +3278,7 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
buf[len++] = '8';
buf[len++] = ';';
}
- } else {
+ } else if (val != 0) {
if (len > buf_size - 10) {
growBuffer(buf);
}
@@ -3174,8 +3303,6 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
}
} else if ((ent != NULL) &&
(ctxt->replaceEntities != 0)) {
- xmlChar *rep;
-
if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) {
rep = xmlStringDecodeEntities(ctxt, ent->content,
XML_SUBSTITUTE_REF,
@@ -3189,6 +3316,7 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
}
}
xmlFree(rep);
+ rep = NULL;
}
} else {
if (len > buf_size - 10) {
@@ -3207,11 +3335,12 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
*/
if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) &&
(ent->content != NULL)) {
- xmlChar *rep;
rep = xmlStringDecodeEntities(ctxt, ent->content,
- XML_SUBSTITUTE_REF, 0, 0, 0);
- if (rep != NULL)
+ XML_SUBSTITUTE_REF, 0, 0, 0);
+ if (rep != NULL) {
xmlFree(rep);
+ rep = NULL;
+ }
}
/*
@@ -3270,6 +3399,10 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt, int *attlen, int normalize) {
mem_error:
xmlErrMemory(ctxt, NULL);
+ if (buf != NULL)
+ xmlFree(buf);
+ if (rep != NULL)
+ xmlFree(rep);
return(NULL);
}
@@ -4538,6 +4671,10 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
(xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE))) {
if (ctxt->myDoc == NULL) {
ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE);
+ if (ctxt->myDoc == NULL) {
+ xmlErrMemory(ctxt, "New Doc failed");
+ return;
+ }
}
if (ctxt->myDoc->intSubset == NULL)
ctxt->myDoc->intSubset = xmlNewDtd(ctxt->myDoc,
@@ -4606,6 +4743,10 @@ xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
(xmlStrEqual(ctxt->myDoc->version, SAX_COMPAT_MODE)))) {
if (ctxt->myDoc == NULL) {
ctxt->myDoc = xmlNewDoc(SAX_COMPAT_MODE);
+ if (ctxt->myDoc == NULL) {
+ xmlErrMemory(ctxt, "New Doc failed");
+ return;
+ }
}
if (ctxt->myDoc->intSubset == NULL)
@@ -5019,6 +5160,8 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
xmlFreeEnumeration(tree);
break;
}
+ if ((type != XML_ATTRIBUTE_CDATA) && (defaultValue != NULL))
+ xmlAttrNormalizeSpace(defaultValue, defaultValue);
GROW;
if (RAW != '>') {
@@ -5108,6 +5251,8 @@ xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt, int inputchk) {
}
NEXT;
ret = xmlNewDocElementContent(ctxt->myDoc, NULL, XML_ELEMENT_CONTENT_PCDATA);
+ if (ret == NULL)
+ return(NULL);
if (RAW == '*') {
ret->ocur = XML_ELEMENT_CONTENT_MULT;
NEXT;
@@ -5338,6 +5483,8 @@ xmlParseElementChildrenContentDecl (xmlParserCtxtPtr ctxt, int inputchk) {
}
} else {
xmlFatalErr(ctxt, XML_ERR_ELEMCONTENT_NOT_FINISHED, NULL);
+ if ((last != NULL) && (last != ret))
+ xmlFreeDocElementContent(ctxt->myDoc, last);
if (ret != NULL)
xmlFreeDocElementContent(ctxt->myDoc, ret);
return(NULL);
@@ -5361,6 +5508,11 @@ xmlParseElementChildrenContentDecl (xmlParserCtxtPtr ctxt, int inputchk) {
return(NULL);
}
last = xmlNewDocElementContent(ctxt->myDoc, elem, XML_ELEMENT_CONTENT_ELEMENT);
+ if (last == NULL) {
+ if (ret != NULL)
+ xmlFreeDocElementContent(ctxt->myDoc, ret);
+ return(NULL);
+ }
if (RAW == '?') {
last->ocur = XML_ELEMENT_CONTENT_OPT;
NEXT;
@@ -5913,6 +6065,21 @@ xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID,
const xmlChar *SystemID) {
xmlDetectSAX2(ctxt);
GROW;
+
+ if ((ctxt->encoding == (const xmlChar *)XML_CHAR_ENCODING_NONE) &&
+ (ctxt->input->end - ctxt->input->cur >= 4)) {
+ xmlChar start[4];
+ xmlCharEncoding enc;
+
+ start[0] = RAW;
+ start[1] = NXT(1);
+ start[2] = NXT(2);
+ start[3] = NXT(3);
+ enc = xmlDetectCharEncoding(start, 4);
+ if (enc != XML_CHAR_ENCODING_NONE)
+ xmlSwitchEncoding(ctxt, enc);
+ }
+
if (CMP5(CUR_PTR, '<', '?', 'x', 'm', 'l')) {
xmlParseTextDecl(ctxt);
if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
@@ -5988,6 +6155,8 @@ xmlParseReference(xmlParserCtxtPtr ctxt) {
int hex = NXT(2);
int value = xmlParseCharRef(ctxt);
+ if (value == 0)
+ return;
if (ctxt->charset != XML_CHAR_ENCODING_UTF8) {
/*
* So we are using non-UTF-8 buffers
@@ -6832,6 +7001,86 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
}
/**
+ * xmlLoadEntityContent:
+ * @ctxt: an XML parser context
+ * @entity: an unloaded system entity
+ *
+ * Load the original content of the given system entity from the
+ * ExternalID/SystemID given. This is to be used for Included in Literal
+ * http://www.w3.org/TR/REC-xml/#inliteral processing of entities references
+ *
+ * Returns 0 in case of success and -1 in case of failure
+ */
+static int
+xmlLoadEntityContent(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
+ xmlParserInputPtr input;
+ xmlBufferPtr buf;
+ int l, c;
+ int count = 0;
+
+ if ((ctxt == NULL) || (entity == NULL) ||
+ ((entity->etype != XML_EXTERNAL_PARAMETER_ENTITY) &&
+ (entity->etype != XML_EXTERNAL_GENERAL_PARSED_ENTITY)) ||
+ (entity->content != NULL)) {
+ xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
+ "xmlLoadEntityContent parameter error");
+ return(-1);
+ }
+
+ if (xmlParserDebugEntities)
+ xmlGenericError(xmlGenericErrorContext,
+ "Reading %s entity content input\n", entity->name);
+
+ buf = xmlBufferCreate();
+ if (buf == NULL) {
+ xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
+ "xmlLoadEntityContent parameter error");
+ return(-1);
+ }
+
+ input = xmlNewEntityInputStream(ctxt, entity);
+ if (input == NULL) {
+ xmlFatalErr(ctxt, XML_ERR_INTERNAL_ERROR,
+ "xmlLoadEntityContent input error");
+ xmlBufferFree(buf);
+ return(-1);
+ }
+
+ /*
+ * Push the entity as the current input, read char by char
+ * saving to the buffer until the end of the entity or an error
+ */
+ xmlPushInput(ctxt, input);
+ GROW;
+ c = CUR_CHAR(l);
+ while ((ctxt->input == input) && (ctxt->input->cur < ctxt->input->end) &&
+ (IS_CHAR(c))) {
+ xmlBufferAdd(buf, ctxt->input->cur, l);
+ if (count++ > 100) {
+ count = 0;
+ GROW;
+ }
+ NEXTL(l);
+ c = CUR_CHAR(l);
+ }
+
+ if ((ctxt->input == input) && (ctxt->input->cur >= ctxt->input->end)) {
+ xmlPopInput(ctxt);
+ } else if (!IS_CHAR(c)) {
+ xmlFatalErrMsgInt(ctxt, XML_ERR_INVALID_CHAR,
+ "xmlLoadEntityContent: invalid char value %d\n",
+ c);
+ xmlBufferFree(buf);
+ return(-1);
+ }
+ entity->content = buf->content;
+ buf->content = NULL;
+ xmlBufferFree(buf);
+
+ return(0);
+}
+
+/**
* xmlParseStringPEReference:
* @ctxt: an XML parser context
* @str: a pointer to an index in the string
@@ -6842,7 +7091,7 @@ xmlParsePEReference(xmlParserCtxtPtr ctxt)
*
* [ WFC: No Recursion ]
* A parsed entity must not contain a recursive
- * reference to itself, either directly or indirectly.
+ * reference to itself, either directly or indirectly.
*
* [ WFC: Entity Declared ]
* In a document without any DTD, a document with only an internal DTD
@@ -7818,9 +8067,10 @@ need_complex:
static const xmlChar *
xmlParseAttribute2(xmlParserCtxtPtr ctxt,
- const xmlChar *pref, const xmlChar *elem,
- const xmlChar **prefix, xmlChar **value,
- int *len, int *alloc) {
+ const xmlChar * pref, const xmlChar * elem,
+ const xmlChar ** prefix, xmlChar ** value,
+ int *len, int *alloc)
+{
const xmlChar *name;
xmlChar *val, *internal_val = NULL;
int normalize = 0;
@@ -7829,9 +8079,9 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
GROW;
name = xmlParseQName(ctxt, prefix);
if (name == NULL) {
- xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
- "error parsing attribute name\n");
- return(NULL);
+ xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
+ "error parsing attribute name\n");
+ return (NULL);
}
/*
@@ -7841,8 +8091,9 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
int type;
type = (int) (long) xmlHashQLookup2(ctxt->attsSpecial,
- pref, elem, *prefix, name);
- if (type != 0) normalize = 1;
+ pref, elem, *prefix, name);
+ if (type != 0)
+ normalize = 1;
}
/*
@@ -7851,54 +8102,71 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
SKIP_BLANKS;
if (RAW == '=') {
NEXT;
- SKIP_BLANKS;
- val = xmlParseAttValueInternal(ctxt, len, alloc, normalize);
- ctxt->instate = XML_PARSER_CONTENT;
+ SKIP_BLANKS;
+ val = xmlParseAttValueInternal(ctxt, len, alloc, normalize);
+ if (normalize) {
+ /*
+ * Sometimes a second normalisation pass for spaces is needed
+ * but that only happens if charrefs or entities refernces
+ * have been used in the attribute value, i.e. the attribute
+ * value have been extracted in an allocated string already.
+ */
+ if (*alloc) {
+ const xmlChar *val2;
+
+ val2 = xmlAttrNormalizeSpace2(ctxt, val, len);
+ if (val2 != NULL) {
+ xmlFree(val);
+ val = (xmlChar *) val2;
+ }
+ }
+ }
+ ctxt->instate = XML_PARSER_CONTENT;
} else {
- xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
- "Specification mandate value for attribute %s\n", name);
- return(NULL);
+ xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
+ "Specification mandate value for attribute %s\n",
+ name);
+ return (NULL);
}
- if (*prefix == ctxt->str_xml) {
- /*
- * Check that xml:lang conforms to the specification
- * No more registered as an error, just generate a warning now
- * since this was deprecated in XML second edition
- */
- if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "lang"))) {
- internal_val = xmlStrndup(val, *len);
- if (!xmlCheckLanguageID(internal_val)) {
- xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE,
- "Malformed value for xml:lang : %s\n",
- internal_val, NULL);
- }
- }
+ if (*prefix == ctxt->str_xml) {
+ /*
+ * Check that xml:lang conforms to the specification
+ * No more registered as an error, just generate a warning now
+ * since this was deprecated in XML second edition
+ */
+ if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "lang"))) {
+ internal_val = xmlStrndup(val, *len);
+ if (!xmlCheckLanguageID(internal_val)) {
+ xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE,
+ "Malformed value for xml:lang : %s\n",
+ internal_val, NULL);
+ }
+ }
- /*
- * Check that xml:space conforms to the specification
- */
- if (xmlStrEqual(name, BAD_CAST "space")) {
- internal_val = xmlStrndup(val, *len);
- if (xmlStrEqual(internal_val, BAD_CAST "default"))
- *(ctxt->space) = 0;
- else if (xmlStrEqual(internal_val, BAD_CAST "preserve"))
- *(ctxt->space) = 1;
- else {
- xmlWarningMsg(ctxt, XML_WAR_SPACE_VALUE,
-"Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n",
- internal_val, NULL);
- }
- }
- if (internal_val) {
- xmlFree(internal_val);
- }
- }
+ /*
+ * Check that xml:space conforms to the specification
+ */
+ if (xmlStrEqual(name, BAD_CAST "space")) {
+ internal_val = xmlStrndup(val, *len);
+ if (xmlStrEqual(internal_val, BAD_CAST "default"))
+ *(ctxt->space) = 0;
+ else if (xmlStrEqual(internal_val, BAD_CAST "preserve"))
+ *(ctxt->space) = 1;
+ else {
+ xmlWarningMsg(ctxt, XML_WAR_SPACE_VALUE,
+ "Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n",
+ internal_val, NULL);
+ }
+ }
+ if (internal_val) {
+ xmlFree(internal_val);
+ }
+ }
*value = val;
- return(name);
+ return (name);
}
-
/**
* xmlParseStartTag2:
* @ctxt: an XML parser context
@@ -8770,6 +9038,7 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
size *= 2;
tmp = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
if (tmp == NULL) {
+ xmlFree(buf);
xmlErrMemory(ctxt, NULL);
return(NULL);
}
@@ -8786,11 +9055,11 @@ xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
/**
* xmlParseVersionInfo:
* @ctxt: an XML parser context
- *
+ *
* parse the XML version.
*
* [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
- *
+ *
* [25] Eq ::= S? '=' S?
*
* Returns the version string, e.g. "1.0"
@@ -10170,7 +10439,20 @@ xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
ctxt->input->cur += tmp;
goto encoding_error;
}
- if ((ctxt->sax != NULL) && (base > 0) &&
+ if ((ctxt->sax != NULL) && (base == 0) &&
+ (ctxt->sax->cdataBlock != NULL) &&
+ (!ctxt->disableSAX)) {
+ /*
+ * Special case to provide identical behaviour
+ * between pull and push parsers on enpty CDATA
+ * sections
+ */
+ if ((ctxt->input->cur - ctxt->input->base >= 9) &&
+ (!strncmp((const char *)&ctxt->input->cur[-9],
+ "<![CDATA[", 9)))
+ ctxt->sax->cdataBlock(ctxt->userData,
+ BAD_CAST "", 0);
+ } else if ((ctxt->sax != NULL) && (base > 0) &&
(!ctxt->disableSAX)) {
if (ctxt->sax->cdataBlock != NULL)
ctxt->sax->cdataBlock(ctxt->userData,
@@ -12012,13 +12294,14 @@ xmlParseInNodeContext(xmlNodePtr node, const char *data, int datalen,
*
* Returns 0 if the chunk is well balanced, -1 in case of args problem and
* the parser error code otherwise
- *
+ *
* In case recover is set to 1, the nodelist will not be empty even if
- * the parsed chunk is not well balanced.
+ * the parsed chunk is not well balanced, assuming the parsing succeeded to
+ * some extent.
*/
int
xmlParseBalancedChunkMemoryRecover(xmlDocPtr doc, xmlSAXHandlerPtr sax,
- void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst,
+ void *user_data, int depth, const xmlChar *string, xmlNodePtr *lst,
int recover) {
xmlParserCtxtPtr ctxt;
xmlDocPtr newDoc;
@@ -12370,7 +12653,6 @@ xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename,
int recovery, void *data) {
xmlDocPtr ret;
xmlParserCtxtPtr ctxt;
- char *directory = NULL;
xmlInitParser();
@@ -12388,10 +12670,8 @@ xmlSAXParseFileWithData(xmlSAXHandlerPtr sax, const char *filename,
ctxt->_private = data;
}
- if ((ctxt->directory == NULL) && (directory == NULL))
- directory = xmlParserGetDirectory(filename);
- if ((ctxt->directory == NULL) && (directory != NULL))
- ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
+ if (ctxt->directory == NULL)
+ ctxt->directory = xmlParserGetDirectory(filename);
ctxt->recovery = recovery;
@@ -12444,9 +12724,10 @@ xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
* @cur: a pointer to an array of xmlChar
*
* parse an XML in-memory document and build a tree.
- * In the case the document is not Well Formed, a tree is built anyway
- *
- * Returns the resulting document tree
+ * In the case the document is not Well Formed, a attempt to build a
+ * tree is tried anyway
+ *
+ * Returns the resulting document tree or NULL in case of failure
*/
xmlDocPtr
@@ -12476,9 +12757,10 @@ xmlParseFile(const char *filename) {
*
* parse an XML file and build a tree. Automatic support for ZLIB/Compress
* compressed document is provided by default if found at compile-time.
- * In the case the document is not Well Formed, a tree is built anyway
+ * In the case the document is not Well Formed, it attempts to build
+ * a tree anyway
*
- * Returns the resulting document tree
+ * Returns the resulting document tree or NULL in case of failure
*/
xmlDocPtr
@@ -12720,9 +13002,10 @@ xmlDocPtr xmlParseMemory(const char *buffer, int size) {
* @size: the size of the array
*
* parse an XML in-memory block and build a tree.
- * In the case the document is not Well Formed, a tree is built anyway
- *
- * Returns the resulting document tree
+ * In the case the document is not Well Formed, an attempt to
+ * build a tree is tried anyway
+ *
+ * Returns the resulting document tree or NULL in case of error
*/
xmlDocPtr xmlRecoverMemory(const char *buffer, int size) {
@@ -12958,12 +13241,15 @@ xmlInitParser(void) {
/**
* xmlCleanupParser:
*
- * Cleanup function for the XML library. It tries to reclaim all
- * parsing related global memory allocated for the library processing.
- * It doesn't deallocate any document related memory. Calling this
- * function should not prevent reusing the library but one should
- * call xmlCleanupParser() only when the process has
- * finished using the library or XML document built with it.
+ * This function name is somewhat misleading. It does not clean up
+ * parser state, it cleans up memory allocated by the library itself.
+ * It is a cleanup function for the XML library. It tries to reclaim all
+ * related global memory allocated for the library processing.
+ * It doesn't deallocate any document related memory. One should
+ * call xmlCleanupParser() only when the process has finished using
+ * the library and all XML/HTML documents built with it.
+ * See also xmlInitParser() which has the opposite function of preparing
+ * the library for operations.
*/
void