From: Michael Schroeder Date: Mon, 20 Sep 2021 13:10:38 +0000 (+0200) Subject: Fix misparsing of '&' in attributes with libxml2 X-Git-Tag: 0.7.20~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a13593b43bd883be6bf4260edbfc8eaf766ffa8;p=thirdparty%2Flibsolv.git Fix misparsing of '&' in attributes with libxml2 For some reason libxml2 insists on re-escaping '&' characters by substituting them with "&". The rpm dependencies are stored in attributes, so this is not an academic matter. Undo the damage done by libxml2 by replacing all & occurences by a single '&'. --- diff --git a/ext/solv_xmlparser.c b/ext/solv_xmlparser.c index 6292663c..87bd0969 100644 --- a/ext/solv_xmlparser.c +++ b/ext/solv_xmlparser.c @@ -53,6 +53,47 @@ character_data(void *userData, const XML_Char *s, int len) xmlp->lcontent += len; } +#ifdef WITH_LIBXML2 +static void fixup_att_inplace(char *at) +{ + while ((at = strchr(at, '&')) != 0) + { + at++; + if (!memcmp(at, "#38;", 4)) + memmove(at, at + 4, strlen(at + 4) + 1); + } +} + +static const xmlChar **fixup_atts(struct solv_xmlparser *xmlp, const xmlChar **atts) +{ + size_t needsize = 0; + size_t natts; + char **at; + + for (natts = 0; atts[natts]; natts++) + if (strchr((char *)atts[natts], '&')) + needsize += strlen((const char *)atts[natts]) + 1; + if (!needsize) + return atts; + at = xmlp->attsdata = solv_realloc(xmlp->attsdata, (natts + 1) * sizeof(xmlChar *) + needsize); + needsize = (natts + 1) * sizeof(xmlChar *); + for (natts = 0; atts[natts]; natts++) + { + at[natts] = (char *)atts[natts]; + if (strchr(at[natts], '&')) + { + size_t l = strlen(at[natts]) + 1; + memcpy((char *)at + needsize, at[natts], l); + at[natts] = (char *)at + needsize; + needsize += l; + fixup_att_inplace(at[natts]); + } + } + at[natts] = 0; + return (const xmlChar **)at; +} +#endif + #ifdef WITH_LIBXML2 static void start_element(void *userData, const xmlChar *name, const xmlChar **atts) @@ -97,6 +138,8 @@ start_element(void *userData, const char *name, const char **atts) static const char *nullattr; atts = (const xmlChar **)&nullattr; } + else if (xmlp->state != oldstate) + atts = fixup_atts(xmlp, atts); #endif if (xmlp->state != oldstate) xmlp->startelement(xmlp, xmlp->state, el->element, (const char **)atts); @@ -177,6 +220,7 @@ solv_xmlparser_free(struct solv_xmlparser *xmlp) queue_free(&xmlp->elementq); xmlp->content = solv_free(xmlp->content); xmlp->errstr = solv_free(xmlp->errstr); + xmlp->attsdata = solv_free(xmlp->attsdata); } static void diff --git a/ext/solv_xmlparser.h b/ext/solv_xmlparser.h index ced0571f..717983f1 100644 --- a/ext/solv_xmlparser.h +++ b/ext/solv_xmlparser.h @@ -30,6 +30,7 @@ struct solv_xmlparser { Id *elementhelper; void *parser; + void *attsdata; }; #define SOLV_XMLPARSER_OK 0