mirror of https://github.com/mpv-player/mpv
playlist: rewrite PLS parser
Somehow the new parser ends up much smaller. Much of it is because we don't parse some additional information. We just skip it, instead of parsing it and then throwing it away. More importantly, we use the physical order of entries, instead of trying to sort them by entry number. Each "File" entry is followed by a number that is supposed to be the entry number, and "File1" is first. (Should it turn out that this is really needed, an additional field should be added to playlist_entry, and then qsort().)
This commit is contained in:
parent
b74edd4069
commit
ed02cbf92f
|
@ -110,6 +110,27 @@ static int parse_mov_rtsptext(struct pl_parser *p)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int parse_pls(struct pl_parser *p)
|
||||
{
|
||||
bstr line = {0};
|
||||
while (!line.len && !pl_eof(p))
|
||||
line = bstr_strip(pl_get_line(p));
|
||||
if (bstrcasecmp0(line, "[playlist]") != 0)
|
||||
return -1;
|
||||
if (p->probing)
|
||||
return 0;
|
||||
while (!pl_eof(p)) {
|
||||
line = bstr_strip(pl_get_line(p));
|
||||
bstr key, value;
|
||||
if (bstr_split_tok(line, "=", &key, &value) &&
|
||||
bstr_case_startswith(key, bstr0("File")))
|
||||
{
|
||||
pl_add(p, value);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct pl_format {
|
||||
const char *name;
|
||||
int (*parse)(struct pl_parser *p);
|
||||
|
@ -119,6 +140,7 @@ static const struct pl_format formats[] = {
|
|||
{"m3u", parse_m3u},
|
||||
{"ini", parse_ref_init},
|
||||
{"mov", parse_mov_rtsptext},
|
||||
{"pls", parse_pls},
|
||||
};
|
||||
|
||||
static const struct pl_format *probe_pl(struct pl_parser *p, bool force)
|
||||
|
|
|
@ -237,145 +237,6 @@ static bool parse_asx(play_tree_parser_t* p) {
|
|||
return asx_parse(p->buffer,p->pl);
|
||||
}
|
||||
|
||||
static char*
|
||||
pls_entry_get_value(char* line) {
|
||||
char* i;
|
||||
|
||||
i = strchr(line,'=');
|
||||
if(!i || i[1] == '\0')
|
||||
return NULL;
|
||||
else
|
||||
return i+1;
|
||||
}
|
||||
|
||||
typedef struct pls_entry {
|
||||
char* file;
|
||||
char* title;
|
||||
char* length;
|
||||
} pls_entry_t;
|
||||
|
||||
static int
|
||||
pls_read_entry(char* line,pls_entry_t** _e,int* _max_entry,char** val) {
|
||||
int num,max_entry = (*_max_entry);
|
||||
pls_entry_t* e = (*_e);
|
||||
int limit = INT_MAX / sizeof(*e);
|
||||
char* v;
|
||||
|
||||
v = pls_entry_get_value(line);
|
||||
if(!v) {
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_ERR,"No value in entry %s\n",line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
num = atoi(line);
|
||||
if(num <= 0 || num > limit) {
|
||||
if (max_entry >= limit) {
|
||||
mp_msg(MSGT_PLAYTREE, MSGL_WARN, "Too many index entries\n");
|
||||
return -1;
|
||||
}
|
||||
num = max_entry+1;
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_WARN,"No or invalid entry index in entry %s\nAssuming %d\n",line,num);
|
||||
}
|
||||
if(num > max_entry) {
|
||||
e = realloc(e, num * sizeof(pls_entry_t));
|
||||
if (!e)
|
||||
return -1;
|
||||
memset(&e[max_entry],0,(num-max_entry)*sizeof(pls_entry_t));
|
||||
max_entry = num;
|
||||
}
|
||||
(*_e) = e;
|
||||
(*_max_entry) = max_entry;
|
||||
(*val) = v;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
static bool parse_pls(play_tree_parser_t* p) {
|
||||
char *line,*v;
|
||||
pls_entry_t* entries = NULL;
|
||||
int n_entries = 0,max_entry=0,num;
|
||||
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_V,"Trying Winamp playlist...\n");
|
||||
while((line = play_tree_parser_get_line(p))) {
|
||||
strstrip(line);
|
||||
if(strlen(line))
|
||||
break;
|
||||
}
|
||||
if (!line)
|
||||
return false;
|
||||
if(strcasecmp(line,"[playlist]"))
|
||||
return false;
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_V,"Detected Winamp playlist format\n");
|
||||
play_tree_parser_stop_keeping(p);
|
||||
line = play_tree_parser_get_line(p);
|
||||
if(!line)
|
||||
return false;
|
||||
strstrip(line);
|
||||
if(strncasecmp(line,"NumberOfEntries",15) == 0) {
|
||||
v = pls_entry_get_value(line);
|
||||
n_entries = atoi(v);
|
||||
if(n_entries < 0)
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Invalid number of entries: very funny!!!\n");
|
||||
else
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Playlist claims to have %d entries. Let's see.\n",n_entries);
|
||||
line = play_tree_parser_get_line(p);
|
||||
}
|
||||
|
||||
while(line) {
|
||||
strstrip(line);
|
||||
if(line[0] == '\0') {
|
||||
line = play_tree_parser_get_line(p);
|
||||
continue;
|
||||
}
|
||||
if(strncasecmp(line,"File",4) == 0) {
|
||||
num = pls_read_entry(line+4,&entries,&max_entry,&v);
|
||||
if(num < 0)
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_ERR,"No value in entry %s\n",line);
|
||||
else
|
||||
entries[num-1].file = strdup(v);
|
||||
} else if(strncasecmp(line,"Title",5) == 0) {
|
||||
num = pls_read_entry(line+5,&entries,&max_entry,&v);
|
||||
if(num < 0)
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_ERR,"No value in entry %s\n",line);
|
||||
else
|
||||
entries[num-1].title = strdup(v);
|
||||
} else if(strncasecmp(line,"Length",6) == 0) {
|
||||
num = pls_read_entry(line+6,&entries,&max_entry,&v);
|
||||
if(num < 0)
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_ERR,"No value in entry %s\n",line);
|
||||
else {
|
||||
char *end;
|
||||
long val = strtol(v, &end, 10);
|
||||
if (*end || (val <= 0 && val != -1))
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Invalid length value in entry %s\n",line);
|
||||
else if (val > 0)
|
||||
entries[num-1].length = strdup(v);
|
||||
}
|
||||
} else
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_WARN,"Unknown entry type %s\n",line);
|
||||
line = play_tree_parser_get_line(p);
|
||||
}
|
||||
|
||||
for(num = 0; num < max_entry ; num++) {
|
||||
if(entries[num].file == NULL)
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Entry %d don't have a file !!!!\n",num+1);
|
||||
else {
|
||||
mp_msg(MSGT_PLAYTREE,MSGL_DBG2,"Adding entry %s\n",entries[num].file);
|
||||
playlist_add_file(p->pl,entries[num].file);
|
||||
if (entries[num].length)
|
||||
playlist_entry_add_param(p->pl->last, bstr0("end"), bstr0(entries[num].length));
|
||||
free(entries[num].file);
|
||||
}
|
||||
// When we have info in playtree we add these info
|
||||
free(entries[num].title);
|
||||
free(entries[num].length);
|
||||
}
|
||||
|
||||
free(entries);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_smil(play_tree_parser_t* p) {
|
||||
int entrymode=0;
|
||||
char* line,source[512],*pos,*s_start,*s_end,*src_line;
|
||||
|
@ -658,7 +519,6 @@ struct playlist *playlist_parse_file(const char *file, struct MPOpts *opts)
|
|||
typedef bool (*parser_fn)(play_tree_parser_t *);
|
||||
static const parser_fn pl_parsers[] = {
|
||||
parse_asx,
|
||||
parse_pls,
|
||||
parse_smil,
|
||||
parse_nsc,
|
||||
parse_textplain
|
||||
|
|
Loading…
Reference in New Issue