Commit f745f60c authored by Rafaël Carré's avatar Rafaël Carré

xspf demux: merge header in C file

remove FREE_ATT, use do { ... } while(0) for FREE_VALUE
use static const tables for xml handlers
use their size to match handlers with tags
replace {SIMPLE,COMPLEX,UNKNOWN}_CONTENT with a bool
parent 7d84269b
......@@ -17,7 +17,6 @@ SOURCES_playlist = \
shoutcast.c \
wpl.c \
xspf.c \
xspf.h \
zpl.c \
$(NULL)
......
/*******************************************************************************
* xspf.c : XSPF playlist import functions
*******************************************************************************
* Copyright (C) 2006 the VideoLAN team
* Copyright (C) 2006-2011 the VideoLAN team
* $Id$
*
* Authors: Daniel Stränger <vlc at schmaller dot de>
......@@ -36,9 +36,39 @@
#include <vlc_xml.h>
#include <vlc_strings.h>
#include <vlc_url.h>
#include "xspf.h"
#include "playlist.h"
#define FREE_VALUE() do { free(psz_value);psz_value=NULL; } while(0)
#define SIMPLE_INTERFACE (input_item_t *p_input,\
const char *psz_name,\
char *psz_value)
#define COMPLEX_INTERFACE (demux_t *p_demux,\
input_item_node_t *p_input_node,\
xml_reader_t *p_xml_reader,\
const char *psz_element)
/* prototypes */
static bool parse_playlist_node COMPLEX_INTERFACE;
static bool parse_tracklist_node COMPLEX_INTERFACE;
static bool parse_track_node COMPLEX_INTERFACE;
static bool parse_extension_node COMPLEX_INTERFACE;
static bool parse_extitem_node COMPLEX_INTERFACE;
static bool set_item_info SIMPLE_INTERFACE;
static bool set_option SIMPLE_INTERFACE;
static bool skip_element COMPLEX_INTERFACE;
/* datatypes */
typedef struct
{
const char *name;
union
{
bool (*smpl) SIMPLE_INTERFACE;
bool (*cmplx) COMPLEX_INTERFACE;
} pf_handler;
bool cmplx;
} xml_elem_hnd_t;
struct demux_sys_t
{
input_item_t **pp_tracklist;
......@@ -136,6 +166,15 @@ static int Control(demux_t *p_demux, int i_query, va_list args)
return VLC_EGENERIC;
}
static const xml_elem_hnd_t *get_handler(const xml_elem_hnd_t *tab, size_t n, const char *name)
{
for (size_t i = 0; i < n / sizeof(xml_elem_hnd_t); i++)
if (!strcmp(name, tab[i].name))
return &tab[i];
return NULL;
}
#define get_handler(tab, name) get_handler(tab, sizeof tab, name)
/**
* \brief parse the root node of a XSPF playlist
* \param p_demux demuxer instance
......@@ -150,27 +189,25 @@ static bool parse_playlist_node COMPLEX_INTERFACE
bool b_version_found = false;
int i_node;
bool b_ret = false;
xml_elem_hnd_t *p_handler = NULL;
xml_elem_hnd_t pl_elements[] =
{ {"title", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"creator", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"annotation", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"info", SIMPLE_CONTENT, {NULL} },
{"location", SIMPLE_CONTENT, {NULL} },
{"identifier", SIMPLE_CONTENT, {NULL} },
{"image", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"date", SIMPLE_CONTENT, {NULL} },
{"license", SIMPLE_CONTENT, {NULL} },
{"attribution", COMPLEX_CONTENT, {.cmplx = skip_element} },
{"link", SIMPLE_CONTENT, {NULL} },
{"meta", SIMPLE_CONTENT, {NULL} },
{"extension", COMPLEX_CONTENT, {.cmplx = parse_extension_node} },
{"trackList", COMPLEX_CONTENT, {.cmplx = parse_tracklist_node} },
{NULL, UNKNOWN_CONTENT, {NULL} }
};
const xml_elem_hnd_t *p_handler = NULL;
/* read all playlist attributes */
static const xml_elem_hnd_t pl_elements[] =
{ {"title", {.smpl = set_item_info}, false },
{"creator", {.smpl = set_item_info}, false },
{"annotation", {.smpl = set_item_info}, false },
{"info", {NULL}, false },
{"location", {NULL}, false },
{"identifier", {NULL}, false },
{"image", {.smpl = set_item_info}, false },
{"date", {NULL}, false },
{"license", {NULL}, false },
{"attribution", {.cmplx = skip_element}, true },
{"link", {NULL}, false },
{"meta", {NULL}, false },
{"extension", {.cmplx = parse_extension_node}, true },
{"trackList", {.cmplx = parse_tracklist_node}, true },
};
/* read all playlist attributes */
const char *name, *value;
while ((name = xml_ReaderNextAttr(p_xml_reader, &value)) != NULL)
{
......@@ -210,20 +247,18 @@ static bool parse_playlist_node COMPLEX_INTERFACE
goto end;
}
/* choose handler */
for (p_handler = pl_elements;
p_handler->name && strcmp(name, p_handler->name);
p_handler++);
if (!p_handler->name)
p_handler = get_handler(pl_elements, name);
if (!p_handler)
{
msg_Err(p_demux, "unexpected element <%s>", name);
goto end;
}
/* complex content is parsed in a separate function */
if (p_handler->type == COMPLEX_CONTENT)
if (p_handler->cmplx)
{
FREE_VALUE();
if (!p_handler->pf_handler.cmplx(p_demux, p_input_node,
p_xml_reader, p_handler->name))
p_xml_reader, p_handler->name))
return false;
p_handler = NULL;
}
......@@ -253,7 +288,7 @@ static bool parse_playlist_node COMPLEX_INTERFACE
if (p_handler->pf_handler.smpl)
p_handler->pf_handler.smpl(p_input_item, p_handler->name, psz_value);
FREE_ATT();
FREE_VALUE();
p_handler = NULL;
break;
}
......@@ -323,20 +358,19 @@ static bool parse_track_node COMPLEX_INTERFACE
int i_node;
static const xml_elem_hnd_t track_elements[] =
{ {"location", SIMPLE_CONTENT, {NULL} },
{"identifier", SIMPLE_CONTENT, {NULL} },
{"title", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"creator", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"annotation", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"info", SIMPLE_CONTENT, {NULL} },
{"image", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"album", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"trackNum", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"duration", SIMPLE_CONTENT, {.smpl = set_item_info} },
{"link", SIMPLE_CONTENT, {NULL} },
{"meta", SIMPLE_CONTENT, {NULL} },
{"extension", COMPLEX_CONTENT, {.cmplx = parse_extension_node} },
{NULL, UNKNOWN_CONTENT, {NULL} }
{ {"location", {NULL}, false },
{"identifier", {NULL}, false },
{"title", {.smpl = set_item_info}, false },
{"creator", {.smpl = set_item_info}, false },
{"annotation", {.smpl = set_item_info}, false },
{"info", {NULL}, false },
{"image", {.smpl = set_item_info}, false },
{"album", {.smpl = set_item_info}, false },
{"trackNum", {.smpl = set_item_info}, false },
{"duration", {.smpl = set_item_info}, false },
{"link", {NULL}, false },
{"meta", {NULL}, false },
{"extension", {.cmplx = parse_extension_node}, true },
};
input_item_t *p_new_input = input_item_New(NULL, NULL);
......@@ -358,16 +392,14 @@ static bool parse_track_node COMPLEX_INTERFACE
goto end;
}
/* choose handler */
for (p_handler = track_elements;
p_handler->name && strcmp(name, p_handler->name);
p_handler++);
if (!p_handler->name)
p_handler = get_handler(track_elements, name);
if (!p_handler)
{
msg_Err(p_demux, "unexpected element <%s>", name);
goto end;
}
/* complex content is parsed in a separate function */
if (p_handler->type == COMPLEX_CONTENT)
if (p_handler->cmplx)
{
FREE_VALUE();
......@@ -477,14 +509,10 @@ static bool parse_track_node COMPLEX_INTERFACE
{
/* there MUST be an item */
if (p_handler->pf_handler.smpl)
{
p_handler->pf_handler.smpl(p_new_input,
p_handler->name,
p_handler->pf_handler.smpl(p_new_input, p_handler->name,
psz_value);
FREE_ATT();
}
}
FREE_ATT();
FREE_VALUE();
p_handler = NULL;
break;
}
......@@ -558,15 +586,14 @@ static bool parse_extension_node COMPLEX_INTERFACE
char *psz_application = NULL;
int i_node;
bool b_release_input_item = false;
xml_elem_hnd_t *p_handler = NULL;
const xml_elem_hnd_t *p_handler = NULL;
input_item_t *p_new_input = NULL;
xml_elem_hnd_t pl_elements[] =
{ {"vlc:node", COMPLEX_CONTENT, {.cmplx = parse_extension_node} },
{"vlc:item", COMPLEX_CONTENT, {.cmplx = parse_extitem_node} },
{"vlc:id", SIMPLE_CONTENT, {NULL} },
{"vlc:option", SIMPLE_CONTENT, {.smpl = set_option} },
{NULL, UNKNOWN_CONTENT, {NULL} }
static const xml_elem_hnd_t pl_elements[] =
{ {"vlc:node", {.cmplx = parse_extension_node}, true },
{"vlc:item", {.cmplx = parse_extitem_node}, true },
{"vlc:id", {NULL}, false },
{"vlc:option", {.smpl = set_option}, false },
};
/* read all extension node attributes */
......@@ -650,23 +677,21 @@ static bool parse_extension_node COMPLEX_INTERFACE
if (!*name)
{
msg_Err(p_demux, "invalid xml stream");
FREE_ATT();
FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input);
return false;
}
/* choose handler */
for (p_handler = pl_elements;
p_handler->name && strcmp(name, p_handler->name);
p_handler++);
if (!p_handler->name)
p_handler = get_handler(pl_elements, name);
if (!p_handler)
{
msg_Err(p_demux, "unexpected element <%s>", name);
FREE_ATT();
FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input);
return false;
}
/* complex content is parsed in a separate function */
if (p_handler->type == COMPLEX_CONTENT)
if (p_handler->cmplx)
{
if (p_handler->pf_handler.cmplx(p_demux,
p_input_node,
......@@ -674,11 +699,11 @@ static bool parse_extension_node COMPLEX_INTERFACE
p_handler->name))
{
p_handler = NULL;
FREE_ATT();
FREE_VALUE();
}
else
{
FREE_ATT();
FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input);
return false;
}
......@@ -687,11 +712,11 @@ static bool parse_extension_node COMPLEX_INTERFACE
case XML_READER_TEXT:
/* simple element content */
FREE_ATT();
FREE_VALUE();
psz_value = strdup(name);
if (unlikely(!psz_value))
{
FREE_ATT();
FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input);
return false;
}
......@@ -702,7 +727,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
/* leave if the current parent node is terminated */
if (!strcmp(name, psz_element))
{
FREE_ATT();
FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input);
return true;
}
......@@ -712,7 +737,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
{
msg_Err(p_demux, "there's no open element left for <%s>",
name);
FREE_ATT();
FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input);
return false;
}
......@@ -727,7 +752,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
p_handler->pf_handler.smpl(p_input_item, p_handler->name,
psz_value);
}
FREE_ATT();
FREE_VALUE();
p_handler = NULL;
break;
}
......
/*****************************************************************************
* Copyright (C) 2006 Daniel Stränger <vlc at schmaller dot de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*******************************************************************************/
/**
* \file modules/demux/playlist/xspf.h
* \brief XSPF playlist import: prototypes, datatypes, defines
*/
/* defines */
#define FREE_VALUE() free(psz_value);psz_value=NULL;
#define FREE_ATT() FREE_VALUE()
enum {
UNKNOWN_CONTENT,
SIMPLE_CONTENT,
COMPLEX_CONTENT
};
#define SIMPLE_INTERFACE (input_item_t *p_input,\
const char *psz_name,\
char *psz_value)
#define COMPLEX_INTERFACE (demux_t *p_demux,\
input_item_node_t *p_input_node,\
xml_reader_t *p_xml_reader,\
const char *psz_element)
/* prototypes */
static bool parse_playlist_node COMPLEX_INTERFACE;
static bool parse_tracklist_node COMPLEX_INTERFACE;
static bool parse_track_node COMPLEX_INTERFACE;
static bool parse_extension_node COMPLEX_INTERFACE;
static bool parse_extitem_node COMPLEX_INTERFACE;
static bool set_item_info SIMPLE_INTERFACE;
static bool set_option SIMPLE_INTERFACE;
static bool skip_element COMPLEX_INTERFACE;
/* datatypes */
typedef struct
{
const char *name;
int type;
union
{
bool (*smpl) SIMPLE_INTERFACE;
bool (*cmplx) COMPLEX_INTERFACE;
} pf_handler;
} xml_elem_hnd_t;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment