Skip to content

Commit 9a13593

Browse files
committed
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 '&'.
1 parent ed88075 commit 9a13593

2 files changed

Lines changed: 45 additions & 0 deletions

File tree

ext/solv_xmlparser.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,47 @@ character_data(void *userData, const XML_Char *s, int len)
5353
xmlp->lcontent += len;
5454
}
5555

56+
#ifdef WITH_LIBXML2
57+
static void fixup_att_inplace(char *at)
58+
{
59+
while ((at = strchr(at, '&')) != 0)
60+
{
61+
at++;
62+
if (!memcmp(at, "#38;", 4))
63+
memmove(at, at + 4, strlen(at + 4) + 1);
64+
}
65+
}
66+
67+
static const xmlChar **fixup_atts(struct solv_xmlparser *xmlp, const xmlChar **atts)
68+
{
69+
size_t needsize = 0;
70+
size_t natts;
71+
char **at;
72+
73+
for (natts = 0; atts[natts]; natts++)
74+
if (strchr((char *)atts[natts], '&'))
75+
needsize += strlen((const char *)atts[natts]) + 1;
76+
if (!needsize)
77+
return atts;
78+
at = xmlp->attsdata = solv_realloc(xmlp->attsdata, (natts + 1) * sizeof(xmlChar *) + needsize);
79+
needsize = (natts + 1) * sizeof(xmlChar *);
80+
for (natts = 0; atts[natts]; natts++)
81+
{
82+
at[natts] = (char *)atts[natts];
83+
if (strchr(at[natts], '&'))
84+
{
85+
size_t l = strlen(at[natts]) + 1;
86+
memcpy((char *)at + needsize, at[natts], l);
87+
at[natts] = (char *)at + needsize;
88+
needsize += l;
89+
fixup_att_inplace(at[natts]);
90+
}
91+
}
92+
at[natts] = 0;
93+
return (const xmlChar **)at;
94+
}
95+
#endif
96+
5697
#ifdef WITH_LIBXML2
5798
static void
5899
start_element(void *userData, const xmlChar *name, const xmlChar **atts)
@@ -97,6 +138,8 @@ start_element(void *userData, const char *name, const char **atts)
97138
static const char *nullattr;
98139
atts = (const xmlChar **)&nullattr;
99140
}
141+
else if (xmlp->state != oldstate)
142+
atts = fixup_atts(xmlp, atts);
100143
#endif
101144
if (xmlp->state != oldstate)
102145
xmlp->startelement(xmlp, xmlp->state, el->element, (const char **)atts);
@@ -177,6 +220,7 @@ solv_xmlparser_free(struct solv_xmlparser *xmlp)
177220
queue_free(&xmlp->elementq);
178221
xmlp->content = solv_free(xmlp->content);
179222
xmlp->errstr = solv_free(xmlp->errstr);
223+
xmlp->attsdata = solv_free(xmlp->attsdata);
180224
}
181225

182226
static void

ext/solv_xmlparser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ struct solv_xmlparser {
3030

3131
Id *elementhelper;
3232
void *parser;
33+
void *attsdata;
3334
};
3435

3536
#define SOLV_XMLPARSER_OK 0

0 commit comments

Comments
 (0)