mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-27 23:55:57 -05:00
179 lines
4.1 KiB
C
179 lines
4.1 KiB
C
#ifndef __MXML_COMPAT_H__
|
|
#define __MXML_COMPAT_H__
|
|
|
|
#include <mxml.h>
|
|
|
|
// mxml 2.10 has a memory leak in mxmlDelete, see https://github.com/michaelrsweet/mxml/issues/183
|
|
// - and since this is the version in Ubuntu 18.04 LTS and Raspian Stretch, we
|
|
// fix it by including a fixed mxmlDelete here. It should be removed once the
|
|
// major distros no longer have 2.10. The below code is msweet's fixed mxml.
|
|
#if (MXML_MAJOR_VERSION == 2) && (MXML_MINOR_VERSION <= 10)
|
|
|
|
#define mxmlDelete compat_mxmlDelete
|
|
|
|
static void
|
|
compat_mxml_free(mxml_node_t *node)
|
|
{
|
|
int i;
|
|
|
|
switch (node->type)
|
|
{
|
|
case MXML_ELEMENT :
|
|
if (node->value.element.name)
|
|
free(node->value.element.name);
|
|
|
|
if (node->value.element.num_attrs)
|
|
{
|
|
for (i = 0; i < node->value.element.num_attrs; i ++)
|
|
{
|
|
if (node->value.element.attrs[i].name)
|
|
free(node->value.element.attrs[i].name);
|
|
if (node->value.element.attrs[i].value)
|
|
free(node->value.element.attrs[i].value);
|
|
}
|
|
|
|
free(node->value.element.attrs);
|
|
}
|
|
break;
|
|
case MXML_INTEGER :
|
|
break;
|
|
case MXML_OPAQUE :
|
|
if (node->value.opaque)
|
|
free(node->value.opaque);
|
|
break;
|
|
case MXML_REAL :
|
|
break;
|
|
case MXML_TEXT :
|
|
if (node->value.text.string)
|
|
free(node->value.text.string);
|
|
break;
|
|
case MXML_CUSTOM :
|
|
if (node->value.custom.data &&
|
|
node->value.custom.destroy)
|
|
(*(node->value.custom.destroy))(node->value.custom.data);
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
|
|
free(node);
|
|
}
|
|
|
|
__attribute__((unused)) static void
|
|
compat_mxmlDelete(mxml_node_t *node)
|
|
{
|
|
mxml_node_t *current,
|
|
*next;
|
|
|
|
if (!node)
|
|
return;
|
|
|
|
mxmlRemove(node);
|
|
for (current = node->child; current; current = next)
|
|
{
|
|
if ((next = current->child) != NULL)
|
|
{
|
|
current->child = NULL;
|
|
continue;
|
|
}
|
|
|
|
if ((next = current->next) == NULL)
|
|
{
|
|
if ((next = current->parent) == node)
|
|
next = NULL;
|
|
}
|
|
compat_mxml_free(current);
|
|
}
|
|
|
|
compat_mxml_free(node);
|
|
}
|
|
#endif
|
|
|
|
// Debian 10.x amd64 w/mxml 2.12 has a mxmlNewTextf that causes segfault when
|
|
// mxmlSaveString or mxmlSaveAllocString is called,
|
|
// ref https://github.com/owntone/owntone-server/issues/938
|
|
#if (MXML_MAJOR_VERSION == 2) && (MXML_MINOR_VERSION == 12)
|
|
|
|
#include <stdarg.h>
|
|
|
|
#define mxmlNewTextf compat_mxmlNewTextf
|
|
|
|
__attribute__((unused)) static mxml_node_t *
|
|
compat_mxmlNewTextf(mxml_node_t *parent, int whitespace, const char *format, ...)
|
|
{
|
|
char *s = NULL;
|
|
va_list va;
|
|
mxml_node_t *node;
|
|
int ret;
|
|
|
|
va_start(va, format);
|
|
ret = vasprintf(&s, format, va);
|
|
va_end(va);
|
|
|
|
if (ret < 0)
|
|
return NULL;
|
|
|
|
node = mxmlNewText(parent, whitespace, s);
|
|
|
|
free(s);
|
|
|
|
return node;
|
|
}
|
|
#endif
|
|
|
|
/* For compability with mxml 2.6 */
|
|
#ifndef HAVE_MXMLGETTEXT
|
|
__attribute__((unused)) static const char * /* O - Text string or NULL */
|
|
mxmlGetText(mxml_node_t *node, /* I - Node to get */
|
|
int *whitespace) /* O - 1 if string is preceded by whitespace, 0 otherwise */
|
|
{
|
|
if (node->type == MXML_TEXT)
|
|
return (node->value.text.string);
|
|
else if (node->type == MXML_ELEMENT &&
|
|
node->child &&
|
|
node->child->type == MXML_TEXT)
|
|
return (node->child->value.text.string);
|
|
else
|
|
return (NULL);
|
|
}
|
|
#endif
|
|
|
|
#ifndef HAVE_MXMLGETOPAQUE
|
|
__attribute__((unused)) static const char * /* O - Opaque string or NULL */
|
|
mxmlGetOpaque(mxml_node_t *node) /* I - Node to get */
|
|
{
|
|
if (!node)
|
|
return (NULL);
|
|
|
|
if (node->type == MXML_OPAQUE)
|
|
return (node->value.opaque);
|
|
else if (node->type == MXML_ELEMENT &&
|
|
node->child &&
|
|
node->child->type == MXML_OPAQUE)
|
|
return (node->child->value.opaque);
|
|
else
|
|
return (NULL);
|
|
}
|
|
#endif
|
|
|
|
#ifndef HAVE_MXMLGETFIRSTCHILD
|
|
__attribute__((unused)) static mxml_node_t * /* O - First child or NULL */
|
|
mxmlGetFirstChild(mxml_node_t *node) /* I - Node to get */
|
|
{
|
|
if (!node || node->type != MXML_ELEMENT)
|
|
return (NULL);
|
|
|
|
return (node->child);
|
|
}
|
|
#endif
|
|
|
|
#ifndef HAVE_MXMLGETTYPE
|
|
__attribute__((unused)) static mxml_type_t /* O - Type of node */
|
|
mxmlGetType(mxml_node_t *node) /* I - Node to get */
|
|
{
|
|
return (node->type);
|
|
}
|
|
#endif
|
|
|
|
#endif /* !__MXML_COMPAT_H__ */
|