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 = \ ...@@ -17,7 +17,6 @@ SOURCES_playlist = \
shoutcast.c \ shoutcast.c \
wpl.c \ wpl.c \
xspf.c \ xspf.c \
xspf.h \
zpl.c \ zpl.c \
$(NULL) $(NULL)
......
/******************************************************************************* /*******************************************************************************
* xspf.c : XSPF playlist import functions * xspf.c : XSPF playlist import functions
******************************************************************************* *******************************************************************************
* Copyright (C) 2006 the VideoLAN team * Copyright (C) 2006-2011 the VideoLAN team
* $Id$ * $Id$
* *
* Authors: Daniel Stränger <vlc at schmaller dot de> * Authors: Daniel Stränger <vlc at schmaller dot de>
...@@ -36,9 +36,39 @@ ...@@ -36,9 +36,39 @@
#include <vlc_xml.h> #include <vlc_xml.h>
#include <vlc_strings.h> #include <vlc_strings.h>
#include <vlc_url.h> #include <vlc_url.h>
#include "xspf.h"
#include "playlist.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 struct demux_sys_t
{ {
input_item_t **pp_tracklist; input_item_t **pp_tracklist;
...@@ -136,6 +166,15 @@ static int Control(demux_t *p_demux, int i_query, va_list args) ...@@ -136,6 +166,15 @@ static int Control(demux_t *p_demux, int i_query, va_list args)
return VLC_EGENERIC; 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 * \brief parse the root node of a XSPF playlist
* \param p_demux demuxer instance * \param p_demux demuxer instance
...@@ -150,27 +189,25 @@ static bool parse_playlist_node COMPLEX_INTERFACE ...@@ -150,27 +189,25 @@ static bool parse_playlist_node COMPLEX_INTERFACE
bool b_version_found = false; bool b_version_found = false;
int i_node; int i_node;
bool b_ret = false; bool b_ret = false;
xml_elem_hnd_t *p_handler = NULL; const 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} }
};
/* 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; const char *name, *value;
while ((name = xml_ReaderNextAttr(p_xml_reader, &value)) != NULL) while ((name = xml_ReaderNextAttr(p_xml_reader, &value)) != NULL)
{ {
...@@ -210,16 +247,14 @@ static bool parse_playlist_node COMPLEX_INTERFACE ...@@ -210,16 +247,14 @@ static bool parse_playlist_node COMPLEX_INTERFACE
goto end; goto end;
} }
/* choose handler */ /* choose handler */
for (p_handler = pl_elements; p_handler = get_handler(pl_elements, name);
p_handler->name && strcmp(name, p_handler->name); if (!p_handler)
p_handler++);
if (!p_handler->name)
{ {
msg_Err(p_demux, "unexpected element <%s>", name); msg_Err(p_demux, "unexpected element <%s>", name);
goto end; goto end;
} }
/* complex content is parsed in a separate function */ /* complex content is parsed in a separate function */
if (p_handler->type == COMPLEX_CONTENT) if (p_handler->cmplx)
{ {
FREE_VALUE(); FREE_VALUE();
if (!p_handler->pf_handler.cmplx(p_demux, p_input_node, if (!p_handler->pf_handler.cmplx(p_demux, p_input_node,
...@@ -253,7 +288,7 @@ static bool parse_playlist_node COMPLEX_INTERFACE ...@@ -253,7 +288,7 @@ static bool parse_playlist_node COMPLEX_INTERFACE
if (p_handler->pf_handler.smpl) if (p_handler->pf_handler.smpl)
p_handler->pf_handler.smpl(p_input_item, p_handler->name, psz_value); p_handler->pf_handler.smpl(p_input_item, p_handler->name, psz_value);
FREE_ATT(); FREE_VALUE();
p_handler = NULL; p_handler = NULL;
break; break;
} }
...@@ -323,20 +358,19 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -323,20 +358,19 @@ static bool parse_track_node COMPLEX_INTERFACE
int i_node; int i_node;
static const xml_elem_hnd_t track_elements[] = static const xml_elem_hnd_t track_elements[] =
{ {"location", SIMPLE_CONTENT, {NULL} }, { {"location", {NULL}, false },
{"identifier", SIMPLE_CONTENT, {NULL} }, {"identifier", {NULL}, false },
{"title", SIMPLE_CONTENT, {.smpl = set_item_info} }, {"title", {.smpl = set_item_info}, false },
{"creator", SIMPLE_CONTENT, {.smpl = set_item_info} }, {"creator", {.smpl = set_item_info}, false },
{"annotation", SIMPLE_CONTENT, {.smpl = set_item_info} }, {"annotation", {.smpl = set_item_info}, false },
{"info", SIMPLE_CONTENT, {NULL} }, {"info", {NULL}, false },
{"image", SIMPLE_CONTENT, {.smpl = set_item_info} }, {"image", {.smpl = set_item_info}, false },
{"album", SIMPLE_CONTENT, {.smpl = set_item_info} }, {"album", {.smpl = set_item_info}, false },
{"trackNum", SIMPLE_CONTENT, {.smpl = set_item_info} }, {"trackNum", {.smpl = set_item_info}, false },
{"duration", SIMPLE_CONTENT, {.smpl = set_item_info} }, {"duration", {.smpl = set_item_info}, false },
{"link", SIMPLE_CONTENT, {NULL} }, {"link", {NULL}, false },
{"meta", SIMPLE_CONTENT, {NULL} }, {"meta", {NULL}, false },
{"extension", COMPLEX_CONTENT, {.cmplx = parse_extension_node} }, {"extension", {.cmplx = parse_extension_node}, true },
{NULL, UNKNOWN_CONTENT, {NULL} }
}; };
input_item_t *p_new_input = input_item_New(NULL, NULL); input_item_t *p_new_input = input_item_New(NULL, NULL);
...@@ -358,16 +392,14 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -358,16 +392,14 @@ static bool parse_track_node COMPLEX_INTERFACE
goto end; goto end;
} }
/* choose handler */ /* choose handler */
for (p_handler = track_elements; p_handler = get_handler(track_elements, name);
p_handler->name && strcmp(name, p_handler->name); if (!p_handler)
p_handler++);
if (!p_handler->name)
{ {
msg_Err(p_demux, "unexpected element <%s>", name); msg_Err(p_demux, "unexpected element <%s>", name);
goto end; goto end;
} }
/* complex content is parsed in a separate function */ /* complex content is parsed in a separate function */
if (p_handler->type == COMPLEX_CONTENT) if (p_handler->cmplx)
{ {
FREE_VALUE(); FREE_VALUE();
...@@ -477,14 +509,10 @@ static bool parse_track_node COMPLEX_INTERFACE ...@@ -477,14 +509,10 @@ static bool parse_track_node COMPLEX_INTERFACE
{ {
/* there MUST be an item */ /* there MUST be an item */
if (p_handler->pf_handler.smpl) 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); psz_value);
FREE_ATT();
}
} }
FREE_ATT(); FREE_VALUE();
p_handler = NULL; p_handler = NULL;
break; break;
} }
...@@ -558,15 +586,14 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -558,15 +586,14 @@ static bool parse_extension_node COMPLEX_INTERFACE
char *psz_application = NULL; char *psz_application = NULL;
int i_node; int i_node;
bool b_release_input_item = false; 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; input_item_t *p_new_input = NULL;
xml_elem_hnd_t pl_elements[] = static const xml_elem_hnd_t pl_elements[] =
{ {"vlc:node", COMPLEX_CONTENT, {.cmplx = parse_extension_node} }, { {"vlc:node", {.cmplx = parse_extension_node}, true },
{"vlc:item", COMPLEX_CONTENT, {.cmplx = parse_extitem_node} }, {"vlc:item", {.cmplx = parse_extitem_node}, true },
{"vlc:id", SIMPLE_CONTENT, {NULL} }, {"vlc:id", {NULL}, false },
{"vlc:option", SIMPLE_CONTENT, {.smpl = set_option} }, {"vlc:option", {.smpl = set_option}, false },
{NULL, UNKNOWN_CONTENT, {NULL} }
}; };
/* read all extension node attributes */ /* read all extension node attributes */
...@@ -650,23 +677,21 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -650,23 +677,21 @@ static bool parse_extension_node COMPLEX_INTERFACE
if (!*name) if (!*name)
{ {
msg_Err(p_demux, "invalid xml stream"); msg_Err(p_demux, "invalid xml stream");
FREE_ATT(); FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input); if (b_release_input_item) vlc_gc_decref(p_new_input);
return false; return false;
} }
/* choose handler */ /* choose handler */
for (p_handler = pl_elements; p_handler = get_handler(pl_elements, name);
p_handler->name && strcmp(name, p_handler->name); if (!p_handler)
p_handler++);
if (!p_handler->name)
{ {
msg_Err(p_demux, "unexpected element <%s>", name); msg_Err(p_demux, "unexpected element <%s>", name);
FREE_ATT(); FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input); if (b_release_input_item) vlc_gc_decref(p_new_input);
return false; return false;
} }
/* complex content is parsed in a separate function */ /* 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, if (p_handler->pf_handler.cmplx(p_demux,
p_input_node, p_input_node,
...@@ -674,11 +699,11 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -674,11 +699,11 @@ static bool parse_extension_node COMPLEX_INTERFACE
p_handler->name)) p_handler->name))
{ {
p_handler = NULL; p_handler = NULL;
FREE_ATT(); FREE_VALUE();
} }
else else
{ {
FREE_ATT(); FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input); if (b_release_input_item) vlc_gc_decref(p_new_input);
return false; return false;
} }
...@@ -687,11 +712,11 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -687,11 +712,11 @@ static bool parse_extension_node COMPLEX_INTERFACE
case XML_READER_TEXT: case XML_READER_TEXT:
/* simple element content */ /* simple element content */
FREE_ATT(); FREE_VALUE();
psz_value = strdup(name); psz_value = strdup(name);
if (unlikely(!psz_value)) if (unlikely(!psz_value))
{ {
FREE_ATT(); FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input); if (b_release_input_item) vlc_gc_decref(p_new_input);
return false; return false;
} }
...@@ -702,7 +727,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -702,7 +727,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
/* leave if the current parent node is terminated */ /* leave if the current parent node is terminated */
if (!strcmp(name, psz_element)) if (!strcmp(name, psz_element))
{ {
FREE_ATT(); FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input); if (b_release_input_item) vlc_gc_decref(p_new_input);
return true; return true;
} }
...@@ -712,7 +737,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -712,7 +737,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
{ {
msg_Err(p_demux, "there's no open element left for <%s>", msg_Err(p_demux, "there's no open element left for <%s>",
name); name);
FREE_ATT(); FREE_VALUE();
if (b_release_input_item) vlc_gc_decref(p_new_input); if (b_release_input_item) vlc_gc_decref(p_new_input);
return false; return false;
} }
...@@ -727,7 +752,7 @@ static bool parse_extension_node COMPLEX_INTERFACE ...@@ -727,7 +752,7 @@ static bool parse_extension_node COMPLEX_INTERFACE
p_handler->pf_handler.smpl(p_input_item, p_handler->name, p_handler->pf_handler.smpl(p_input_item, p_handler->name,
psz_value); psz_value);
} }
FREE_ATT(); FREE_VALUE();
p_handler = NULL; p_handler = NULL;
break; 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