]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Fix misparsing of '&' in attributes with libxml2
authorMichael Schroeder <mls@suse.de>
Fri, 4 Mar 2022 10:47:05 +0000 (11:47 +0100)
committerMichael Schroeder <mls@suse.de>
Fri, 4 Mar 2022 10:47:05 +0000 (11:47 +0100)
For some reason libxml2 insists on re-escaping '&' characters
by substituting them with "&#38;". The rpm dependencies are
stored in attributes, so this is not an academic matter.

Undo the damage done by libxml2 by replacing all &#38; occurences
by a single '&'.

ext/solv_xmlparser.c
ext/solv_xmlparser.h

index 170520ff3901c4abf0c380875addd964d722eb8a..63e550837a13e9994aed69cb14e962adb88e1ebf 100644 (file)
@@ -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);
@@ -178,6 +221,7 @@ solv_xmlparser_free(struct solv_xmlparser *xmlp)
   xmlp->elementhelper = solv_free(xmlp->elementhelper);
   queue_free(&xmlp->elementq);
   xmlp->content = solv_free(xmlp->content);
+  xmlp->attsdata = solv_free(xmlp->attsdata);
 }
 
 #ifdef WITH_LIBXML2
index 9fb342f42b687ea809f116efa2a2be5ee96ad4f5..ac34b501b287e9f7bf5581f79e64a7e1b38f6b60 100644 (file)
@@ -28,6 +28,7 @@ struct solv_xmlparser {
 
   Id *elementhelper;
   void *parser;
+  void *attsdata;
 };
 
 static inline const char *