[misc] Add misc_xml.c to wrap mxml, fixes XML reading of CDATA (et al)

The change removes all direct calls to mxml from the modules that need an XML
parser (lastfm.c, pipe.c, rssscanner.c and httpd_rsp.c).

Even with the help of mxml, reading XML is hard, so a layer is added which
helps deal with stuff like whitespace and CDATA. This should make OwnTone more
resilient to any XML variations it might receive.

The changes fixes issue #1677.
This commit is contained in:
ejurgensen
2023-11-10 17:40:17 +01:00
parent 83ac327d7f
commit 65c72c484b
8 changed files with 648 additions and 497 deletions

View File

@@ -52,10 +52,9 @@
#include <event2/event.h>
#include <event2/buffer.h>
#include "mxml-compat.h"
#include "input.h"
#include "misc.h"
#include "misc_xml.h"
#include "logger.h"
#include "db.h"
#include "conffile.h"
@@ -531,35 +530,33 @@ log_incoming(int severity, const char *msg, uint32_t type, uint32_t code, int da
DPRINTF(severity, L_PLAYER, "%s (type=%s, code=%s, len=%d)\n", msg, typestr, codestr, data_len);
}
/* Example of xml item:
<item><type>73736e63</type><code>6d647374</code><length>9</length>
<data encoding="base64">
NDE5OTg3OTU0</data></item>
*/
static int
parse_item_xml(uint32_t *type, uint32_t *code, uint8_t **data, int *data_len, const char *item)
{
mxml_node_t *xml;
mxml_node_t *haystack;
mxml_node_t *needle;
xml_node *xml;
const char *s;
xml = mxmlNewXML("1.0");
// DPRINTF(E_DBG, L_PLAYER, "Got pipe metadata item: '%s'\n", item);
xml = xml_from_string(item);
if (!xml)
return -1;
// DPRINTF(E_DBG, L_PLAYER, "Parsing %s\n", item);
haystack = mxmlLoadString(xml, item, MXML_NO_CALLBACK);
if (!haystack)
{
DPRINTF(E_LOG, L_PLAYER, "Could not parse pipe metadata: %s\n", item);
DPRINTF(E_LOG, L_PLAYER, "Could not parse pipe metadata item: %s\n", item);
goto error;
}
*type = 0;
if ( (needle = mxmlFindElement(haystack, haystack, "type", NULL, NULL, MXML_DESCEND)) &&
(s = mxmlGetText(needle, NULL)) )
if ((s = xml_get_val(xml, "item/type")))
sscanf(s, "%8x", type);
*code = 0;
if ( (needle = mxmlFindElement(haystack, haystack, "code", NULL, NULL, MXML_DESCEND)) &&
(s = mxmlGetText(needle, NULL)) )
if ((s = xml_get_val(xml, "item/code")))
sscanf(s, "%8x", code);
if (*type == 0 || *code == 0)
@@ -570,8 +567,7 @@ parse_item_xml(uint32_t *type, uint32_t *code, uint8_t **data, int *data_len, co
*data = NULL;
*data_len = 0;
if ( (needle = mxmlFindElement(haystack, haystack, "data", NULL, NULL, MXML_DESCEND)) &&
(s = mxmlGetText(needle, NULL)) )
if ((s = xml_get_val(xml, "item/data")))
{
*data = b64_decode(data_len, s);
if (*data == NULL)
@@ -583,11 +579,11 @@ parse_item_xml(uint32_t *type, uint32_t *code, uint8_t **data, int *data_len, co
log_incoming(E_SPAM, "Read Shairport metadata", *type, *code, *data_len);
mxmlDelete(xml);
xml_free(xml);
return 0;
error:
mxmlDelete(xml);
xml_free(xml);
return -1;
}