From abcc225763e543b75baaa4ff11342e911194910d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 10 Feb 2012 00:12:29 +0100 Subject: cue_parser: new line based CUE sheet parser To replace libcue, the unmaintained and crashy library. --- Makefile.am | 19 +-- NEWS | 1 + configure.ac | 18 +- src/cue/cue_parser.c | 327 +++++++++++++++++++++++++++++++++++++ src/cue/cue_parser.h | 58 +++++++ src/cue/cue_tag.c | 244 --------------------------- src/cue/cue_tag.h | 23 --- src/playlist/cue_playlist_plugin.c | 89 ++++------ src/playlist_list.c | 2 - 9 files changed, 421 insertions(+), 360 deletions(-) create mode 100644 src/cue/cue_parser.c create mode 100644 src/cue/cue_parser.h delete mode 100644 src/cue/cue_tag.c delete mode 100644 src/cue/cue_tag.h diff --git a/Makefile.am b/Makefile.am index 00edcfdd..efdaa4d3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -218,7 +218,6 @@ mpd_headers = \ src/archive/iso9660_archive_plugin.h \ src/archive/zzip_archive_plugin.h \ src/input/archive_input_plugin.h \ - src/cue/cue_tag.h\ src/mpd_error.h src_mpd_SOURCES = \ @@ -239,6 +238,7 @@ src_mpd_SOURCES = \ src/cmdline.c \ src/conf.c \ src/crossfade.c \ + src/cue/cue_parser.c src/cue/cue_parser.h \ src/dbUtils.c \ src/decoder_thread.c \ src/decoder_control.c \ @@ -478,8 +478,7 @@ libdecoder_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \ $(MPG123_CFLAGS) \ $(FFMPEG_CFLAGS) \ $(MPCDEC_CFLAGS) \ - $(FAAD_CFLAGS) \ - $(CUE_CFLAGS) + $(FAAD_CFLAGS) DECODER_LIBS = \ libdecoder_plugins.a \ @@ -497,8 +496,7 @@ DECODER_LIBS = \ $(MP4FF_LIBS) \ $(FFMPEG_LIBS) \ $(MPCDEC_LIBS) \ - $(FAAD_LIBS) \ - $(CUE_LIBS) + $(FAAD_LIBS) DECODER_SRC = @@ -858,10 +856,10 @@ libplaylist_plugins_a_SOURCES = \ src/playlist/xspf_playlist_plugin.c \ src/playlist/asx_playlist_plugin.c \ src/playlist/rss_playlist_plugin.c \ + src/playlist/cue_playlist_plugin.c \ src/playlist_list.c libplaylist_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \ - $(patsubst -I%/FLAC,-I%,$(FLAC_CFLAGS)) \ - $(CUE_CFLAGS) + $(patsubst -I%/FLAC,-I%,$(FLAC_CFLAGS)) PLAYLIST_LIBS = \ libplaylist_plugins.a \ @@ -875,11 +873,6 @@ if ENABLE_DESPOTIFY libplaylist_plugins_a_SOURCES += src/playlist/despotify_playlist_plugin.c endif -if HAVE_CUE -libplaylist_plugins_a_SOURCES += src/playlist/cue_playlist_plugin.c -libplaylist_plugins_a_SOURCES += src/cue/cue_tag.c -endif - if HAVE_FLAC libplaylist_plugins_a_SOURCES += src/playlist/flac_playlist_plugin.c endif @@ -998,7 +991,6 @@ test_run_input_SOURCES = test/run_input.c \ test_dump_playlist_LDADD = \ $(PLAYLIST_LIBS) \ - $(CUE_LIBS) \ $(FLAC_LIBS) \ $(INPUT_LIBS) \ $(ARCHIVE_LIBS) \ @@ -1009,6 +1001,7 @@ test_dump_playlist_SOURCES = test/dump_playlist.c \ src/uri.c \ src/song.c src/tag.c src/tag_pool.c src/tag_save.c \ src/text_input_stream.c src/fifo_buffer.c \ + src/cue/cue_parser.c src/cue/cue_parser.h \ src/fd_util.c if HAVE_FLAC diff --git a/NEWS b/NEWS index 7d3ffac9..977762e0 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,7 @@ ver 0.17 (2011/??/??) - alsa: listen for external volume changes * playlist: - allow references to songs outside the music directory + - new CUE parser, without libcue * state_file: add option "restore_paused" * cue: show CUE track numbers * allow port specification in "bind_to_address" settings diff --git a/configure.ac b/configure.ac index bcf54033..3a1bc465 100644 --- a/configure.ac +++ b/configure.ac @@ -157,11 +157,6 @@ AC_ARG_ENABLE(cdio-paranoia, [enable support for audio CD support]),, enable_cdio_paranoia=auto) -AC_ARG_ENABLE(cue, - AS_HELP_STRING([--enable-cue], - [enable support for libcue support]),, - enable_cue=auto) - AC_ARG_ENABLE(curl, AS_HELP_STRING([--enable-curl], [enable support for libcurl HTTP streaming (default: auto)]),, @@ -539,16 +534,6 @@ dnl --------------------------------------------------------------------------- dnl Metadata Plugins dnl --------------------------------------------------------------------------- -dnl ---------------------------------- libcue --------------------------------- -MPD_AUTO_PKG(cue, CUE, [libcue], - [libcue parsing library], [libcue not found]) -if test x$enable_cue = xyes; then - AC_DEFINE([HAVE_CUE], 1, - [Define to enable libcue support]) -fi - -AM_CONDITIONAL(HAVE_CUE, test x$enable_cue = xyes) - dnl -------------------------------- libid3tag -------------------------------- MPD_AUTO_PKG_LIB(id3, ID3TAG, id3tag, id3tag, id3_file_open, [-lid3tag -lz], [], [id3tag], [libid3tag not found]) @@ -686,7 +671,7 @@ if test x$enable_despotify = xyes; then fi AM_CONDITIONAL(ENABLE_DESPOTIFY, test x$enable_despotify = xyes) -dnl ---------------------------------- libcue --------------------------------- +dnl ---------------------------------- cdio --------------------------------- MPD_AUTO_PKG(cdio_paranoia, CDIO_PARANOIA, [libcdio_paranoia], [libcdio_paranoia audio CD library], [libcdio_paranoia not found]) if test x$enable_cdio_paranoia = xyes; then @@ -1547,7 +1532,6 @@ results(inotify, [inotify]) results(sqlite, [SQLite]) printf '\nMetadata support:\n\t' -results(cue,[cue]) results(id3,[ID3]) printf '\nPlayback support:\n\t' diff --git a/src/cue/cue_parser.c b/src/cue/cue_parser.c new file mode 100644 index 00000000..034d4a1f --- /dev/null +++ b/src/cue/cue_parser.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +#include "config.h" +#include "cue_parser.h" +#include "string_util.h" +#include "song.h" +#include "tag.h" + +#include +#include + +struct cue_parser { + enum { + /** + * Parsing the CUE header. + */ + HEADER, + + /** + * Parsing a "FILE ... WAVE". + */ + WAVE, + + /** + * Ignore everything until the next "FILE". + */ + IGNORE_FILE, + + /** + * Parsing a "TRACK ... AUDIO". + */ + TRACK, + + /** + * Ignore everything until the next "TRACK". + */ + IGNORE_TRACK, + } state; + + struct tag *tag; + + char *filename; + + struct song *current, *previous, *finished; + + bool last_updated; +}; + +struct cue_parser * +cue_parser_new(void) +{ + struct cue_parser *parser = g_new(struct cue_parser, 1); + parser->state = HEADER; + parser->tag = tag_new(); + parser->filename = NULL; + parser->current = NULL; + parser->previous = NULL; + parser->finished = NULL; + return parser; +} + +void +cue_parser_free(struct cue_parser *parser) +{ + tag_free(parser->tag); + g_free(parser->filename); + + if (parser->current != NULL) + song_free(parser->current); + + if (parser->finished != NULL) + song_free(parser->finished); + + g_free(parser); +} + +static const char * +cue_next_word(char *p, char **pp) +{ + assert(p >= *pp); + assert(!g_ascii_isspace(*p)); + + const char *word = p; + while (*p != 0 && !g_ascii_isspace(*p)) + ++p; + + *p = 0; + *pp = p + 1; + return word; +} + +static const char * +cue_next_quoted(char *p, char **pp) +{ + assert(p >= *pp); + assert(p[-1] == '"'); + + char *end = strchr(p, '"'); + if (end == NULL) { + /* syntax error - ignore it silently */ + *pp = p + strlen(p); + return p; + } + + *end = 0; + *pp = end + 1; + + return p; +} + +static const char * +cue_next_token(char **pp) +{ + char *p = strchug_fast(*pp); + if (*p == 0) + return NULL; + + return cue_next_word(p, pp); +} + +static const char * +cue_next_value(char **pp) +{ + char *p = strchug_fast(*pp); + if (*p == 0) + return NULL; + + if (*p == '"') + return cue_next_quoted(p + 1, pp); + else + return cue_next_word(p, pp); +} + +static void +cue_add_tag(struct tag *tag, enum tag_type type, char *p) +{ + const char *value = cue_next_value(&p); + if (value != NULL) + tag_add_item(tag, type, value); + +} + +static void +cue_parse_rem(char *p, struct tag *tag) +{ + const char *type = cue_next_token(&p); + if (type == NULL) + return; + + enum tag_type type2 = tag_name_parse_i(type); + if (type2 != TAG_NUM_OF_ITEM_TYPES) + cue_add_tag(tag, type2, p); +} + +static struct tag * +cue_current_tag(struct cue_parser *parser) +{ + if (parser->state == HEADER) + return parser->tag; + else if (parser->state == TRACK) + return parser->current->tag; + else + return NULL; +} + +static int +cue_parse_position(const char *p) +{ + char *endptr; + unsigned long minutes = strtoul(p, &endptr, 10); + if (endptr == p || *endptr != ':') + return -1; + + p = endptr + 1; + unsigned long seconds = strtoul(p, &endptr, 10); + if (endptr == p || *endptr != ':') + return -1; + + p = endptr + 1; + unsigned long frames = strtoul(p, &endptr, 10); + if (endptr == p || *endptr != 0) + return -1; + + return minutes * 60000 + seconds * 1000 + frames * 1000 / 75; +} + +static void +cue_parser_feed2(struct cue_parser *parser, char *p) +{ + assert(parser != NULL); + assert(p != NULL); + + const char *command = cue_next_token(&p); + if (command == NULL) + return; + + if (strcmp(command, "REM") == 0) { + struct tag *tag = cue_current_tag(parser); + if (tag != NULL) + cue_parse_rem(p, tag); + } else if (strcmp(command, "PERFORMER") == 0) { + struct tag *tag = cue_current_tag(parser); + if (tag != NULL) + cue_add_tag(tag, TAG_PERFORMER, p); + } else if (strcmp(command, "TITLE") == 0) { + if (parser->state == HEADER) + cue_add_tag(parser->tag, TAG_ALBUM, p); + else if (parser->state == TRACK) + cue_add_tag(parser->current->tag, TAG_TITLE, p); + } else if (strcmp(command, "FILE") == 0) { + cue_parser_finish(parser); + + const char *filename = cue_next_value(&p); + if (filename == NULL) + return; + + const char *type = cue_next_token(&p); + if (type == NULL) + return; + + if (strcmp(type, "WAVE") != 0) { + parser->state = IGNORE_FILE; + return; + } + + parser->state = WAVE; + g_free(parser->filename); + parser->filename = g_strdup(filename); + } else if (parser->state == IGNORE_FILE) { + return; + } else if (strcmp(command, "TRACK") == 0) { + cue_parser_finish(parser); + + const char *nr = cue_next_token(&p); + if (nr == NULL) + return; + + const char *type = cue_next_token(&p); + if (type == NULL) + return; + + if (strcmp(type, "AUDIO") != 0) { + parser->state = IGNORE_TRACK; + return; + } + + parser->state = TRACK; + parser->current = song_remote_new(parser->filename); + assert(parser->current->tag == NULL); + parser->current->tag = tag_dup(parser->tag); + tag_add_item(parser->current->tag, TAG_TRACK, nr); + parser->last_updated = false; + } else if (parser->state == IGNORE_TRACK) { + return; + } else if (parser->state == TRACK && strcmp(command, "INDEX") == 0) { + const char *nr = cue_next_token(&p); + if (nr == NULL) + return; + + const char *position = cue_next_token(&p); + if (position == NULL) + return; + + int position_ms = cue_parse_position(position); + if (position_ms < 0) + return; + + if (!parser->last_updated && parser->previous != NULL && + parser->previous->start_ms < (unsigned)position_ms) { + parser->last_updated = true; + parser->previous->end_ms = position_ms; + parser->previous->tag->time = + (parser->previous->end_ms - parser->previous->start_ms + 500) / 1000; + } + + parser->current->start_ms = position_ms; + } +} + +void +cue_parser_feed(struct cue_parser *parser, const char *line) +{ + assert(parser != NULL); + assert(line != NULL); + + char *allocated = g_strdup(line); + cue_parser_feed2(parser, allocated); + g_free(allocated); +} + +void +cue_parser_finish(struct cue_parser *parser) +{ + if (parser->finished != NULL) + song_free(parser->finished); + + parser->finished = parser->previous; + parser->previous = parser->current; + parser->current = NULL; +} + +struct song * +cue_parser_get(struct cue_parser *parser) +{ + assert(parser != NULL); + + struct song *song = parser->finished; + parser->finished = NULL; + return song; +} diff --git a/src/cue/cue_parser.h b/src/cue/cue_parser.h new file mode 100644 index 00000000..d8d69573 --- /dev/null +++ b/src/cue/cue_parser.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2003-2011 The Music Player Daemon Project + * http://www.musicpd.org + * + * 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. + */ + +#ifndef MPD_CUE_PARSER_H +#define MPD_CUE_PARSER_H + +#include "check.h" + +#include + +struct cue_parser * +cue_parser_new(void); + +void +cue_parser_free(struct cue_parser *parser); + +/** + * Feed a text line from the CUE file into the parser. Call + * cue_parser_get() after this to see if a song has been finished. + */ +void +cue_parser_feed(struct cue_parser *parser, const char *line); + +/** + * Tell the parser that the end of the file has been reached. Call + * cue_parser_get() after this to see if a song has been finished. + * This procedure must be done twice! + */ +void +cue_parser_finish(struct cue_parser *parser); + +/** + * Check if a song was finished by the last cue_parser_feed() or + * cue_parser_finish() call. + * + * @return a song object that must be freed by the caller, or NULL if + * no song was finished at this time + */ +struct song * +cue_parser_get(struct cue_parser *parser); + +#endif diff --git a/src/cue/cue_tag.c b/src/cue/cue_tag.c deleted file mode 100644 index 6ee38bbd..00000000 --- a/src/cue/cue_tag.c +++ /dev/null @@ -1,244 +0,0 @@ -#include "config.h" -#include "cue_tag.h" -#include "tag.h" - -#include -#include - -static struct tag * -cue_tag_cd(struct Cdtext *cdtext, struct Rem *rem) -{ - struct tag *tag; - char *tmp; - - assert(cdtext != NULL); - - tag = tag_new(); - - tag_begin_add(tag); - - /* TAG_ALBUM_ARTIST */ - if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL) - tag_add_item(tag, TAG_ALBUM_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_SONGWRITER, cdtext)) != NULL) - tag_add_item(tag, TAG_ALBUM_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL) - tag_add_item(tag, TAG_ALBUM_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_ARRANGER, cdtext)) != NULL) - tag_add_item(tag, TAG_ALBUM_ARTIST, tmp); - - /* TAG_ARTIST */ - if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_SONGWRITER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_ARRANGER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - /* TAG_PERFORMER */ - if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL) - tag_add_item(tag, TAG_PERFORMER, tmp); - - /* TAG_COMPOSER */ - if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL) - tag_add_item(tag, TAG_COMPOSER, tmp); - - /* TAG_ALBUM */ - if ((tmp = cdtext_get(PTI_TITLE, cdtext)) != NULL) - tag_add_item(tag, TAG_ALBUM, tmp); - - /* TAG_GENRE */ - if ((tmp = cdtext_get(PTI_GENRE, cdtext)) != NULL) - tag_add_item(tag, TAG_GENRE, tmp); - - /* TAG_DATE */ - if ((tmp = rem_get(REM_DATE, rem)) != NULL) - tag_add_item(tag, TAG_DATE, tmp); - - /* TAG_COMMENT */ - if ((tmp = cdtext_get(PTI_MESSAGE, cdtext)) != NULL) - tag_add_item(tag, TAG_COMMENT, tmp); - - /* TAG_DISC */ - if ((tmp = cdtext_get(PTI_DISC_ID, cdtext)) != NULL) - tag_add_item(tag, TAG_DISC, tmp); - - /* stream name, usually empty - * tag_add_item(tag, TAG_NAME,); - */ - - /* REM MUSICBRAINZ entry? - tag_add_item(tag, TAG_MUSICBRAINZ_ARTISTID,); - tag_add_item(tag, TAG_MUSICBRAINZ_ALBUMID,); - tag_add_item(tag, TAG_MUSICBRAINZ_ALBUMARTISTID,); - tag_add_item(tag, TAG_MUSICBRAINZ_TRACKID,); - */ - - tag_end_add(tag); - - if (tag_is_empty(tag)) { - tag_free(tag); - return NULL; - } - - return tag; -} - -static struct tag * -cue_tag_track(struct Cdtext *cdtext, struct Rem *rem) -{ - struct tag *tag; - char *tmp; - - assert(cdtext != NULL); - - tag = tag_new(); - - tag_begin_add(tag); - - /* TAG_ARTIST */ - if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_SONGWRITER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - else if ((tmp = cdtext_get(PTI_ARRANGER, cdtext)) != NULL) - tag_add_item(tag, TAG_ARTIST, tmp); - - /* TAG_TITLE */ - if ((tmp = cdtext_get(PTI_TITLE, cdtext)) != NULL) - tag_add_item(tag, TAG_TITLE, tmp); - - /* TAG_GENRE */ - if ((tmp = cdtext_get(PTI_GENRE, cdtext)) != NULL) - tag_add_item(tag, TAG_GENRE, tmp); - - /* TAG_DATE */ - if ((tmp = rem_get(REM_DATE, rem)) != NULL) - tag_add_item(tag, TAG_DATE, tmp); - - /* TAG_COMPOSER */ - if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL) - tag_add_item(tag, TAG_COMPOSER, tmp); - - /* TAG_PERFORMER */ - if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL) - tag_add_item(tag, TAG_PERFORMER, tmp); - - /* TAG_COMMENT */ - if ((tmp = cdtext_get(PTI_MESSAGE, cdtext)) != NULL) - tag_add_item(tag, TAG_COMMENT, tmp); - - /* TAG_DISC */ - if ((tmp = cdtext_get(PTI_DISC_ID, cdtext)) != NULL) - tag_add_item(tag, TAG_DISC, tmp); - - tag_end_add(tag); - - if (tag_is_empty(tag)) { - tag_free(tag); - return NULL; - } - - return tag; -} - -struct tag * -cue_tag(struct Cd *cd, unsigned tnum) -{ - struct tag *cd_tag, *track_tag, *tag; - struct Track *track; - - assert(cd != NULL); - - track = cd_get_track(cd, tnum); - if (track == NULL) - return NULL; - - /* tag from CDtext info */ - cd_tag = cue_tag_cd(cd_get_cdtext(cd), cd_get_rem(cd)); - - /* tag from TRACKtext info */ - track_tag = cue_tag_track(track_get_cdtext(track), - track_get_rem(track)); - - tag = tag_merge_replace(cd_tag, track_tag); - if (tag == NULL) - return NULL; - - /* Create a tag number */ - - tag_clear_items_by_type(tag, TAG_TRACK); - - char convert_uinttostring[8]; - snprintf(convert_uinttostring, sizeof(convert_uinttostring), - "%02d/%02d", tnum, cd_get_ntrack(cd)); - tag_add_item(tag, TAG_TRACK, convert_uinttostring); - - tag->time = track_get_length(track) - - track_get_index(track, 1) - + track_get_zero_pre(track); - track = cd_get_track(cd, tnum + 1); - if (track != NULL) - tag->time += track_get_index(track, 1) - - track_get_zero_pre(track); - /* libcue returns the track duration in frames, and there are - 75 frames per second; this formula rounds down */ - tag->time = tag->time / 75; - - return tag; -} - -struct tag * -cue_tag_file(FILE *fp, unsigned tnum) -{ - struct Cd *cd; - struct tag *tag; - - assert(fp != NULL); - - if (tnum > 256) - return NULL; - - cd = cue_parse_file(fp); - if (cd == NULL) - return NULL; - - tag = cue_tag(cd, tnum); - cd_delete(cd); - - return tag; -} - -struct tag * -cue_tag_string(const char *str, unsigned tnum) -{ - struct Cd *cd; - struct tag *tag; - - assert(str != NULL); - - if (tnum > 256) - return NULL; - - cd = cue_parse_string(str); - if (cd == NULL) - return NULL; - - tag = cue_tag(cd, tnum); - cd_delete(cd); - - return tag; -} diff --git a/src/cue/cue_tag.h b/src/cue/cue_tag.h deleted file mode 100644 index 1ddaa59c..00000000 --- a/src/cue/cue_tag.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef MPD_CUE_TAG_H -#define MPD_CUE_TAG_H - -#include "check.h" - -#ifdef HAVE_CUE /* libcue */ - -#include - -struct tag; -struct Cd; - -struct tag * -cue_tag(struct Cd *cd, unsigned tnum); - -struct tag * -cue_tag_file(FILE *file, unsigned tnum); - -struct tag * -cue_tag_string(const char *str, unsigned tnum); - -#endif /* libcue */ -#endif diff --git a/src/playlist/cue_playlist_plugin.c b/src/playlist/cue_playlist_plugin.c index 3f2d5b34..b85de77d 100644 --- a/src/playlist/cue_playlist_plugin.c +++ b/src/playlist/cue_playlist_plugin.c @@ -22,10 +22,11 @@ #include "playlist_plugin.h" #include "tag.h" #include "song.h" -#include "cue/cue_tag.h" +#include "cue/cue_parser.h" +#include "input_stream.h" +#include "text_input_stream.h" #include -#include #include #include @@ -35,32 +36,21 @@ struct cue_playlist { struct playlist_provider base; - struct Cd *cd; - - unsigned next; + struct input_stream *is; + struct text_input_stream *tis; + struct cue_parser *parser; }; static struct playlist_provider * -cue_playlist_open_uri(const char *uri, - G_GNUC_UNUSED GMutex *mutex, G_GNUC_UNUSED GCond *cond) +cue_playlist_open_stream(struct input_stream *is) { - struct cue_playlist *playlist; - FILE *file; - struct Cd *cd; - - file = fopen(uri, "rt"); - if (file == NULL) - return NULL; + struct cue_playlist *playlist = g_new(struct cue_playlist, 1); + playlist_provider_init(&playlist->base, &cue_playlist_plugin); - cd = cue_parse_file(file); - fclose(file); - if (cd == NULL) - return NULL; + playlist->is = is; + playlist->tis = text_input_stream_new(is); + playlist->parser = cue_parser_new(); - playlist = g_new(struct cue_playlist, 1); - playlist_provider_init(&playlist->base, &cue_playlist_plugin); - playlist->cd = cd; - playlist->next = 1; return &playlist->base; } @@ -70,7 +60,8 @@ cue_playlist_close(struct playlist_provider *_playlist) { struct cue_playlist *playlist = (struct cue_playlist *)_playlist; - cd_delete(playlist->cd); + cue_parser_free(playlist->parser); + text_input_stream_free(playlist->tis); g_free(playlist); } @@ -78,45 +69,21 @@ static struct song * cue_playlist_read(struct playlist_provider *_playlist) { struct cue_playlist *playlist = (struct cue_playlist *)_playlist; - struct Track *track; - struct tag *tag; - const char *filename; - struct song *song; - - track = cd_get_track(playlist->cd, playlist->next); - if (track == NULL) - return NULL; - - tag = cue_tag(playlist->cd, playlist->next); - if (tag == NULL) - return NULL; - - ++playlist->next; - - filename = track_get_filename(track); - if (*filename == 0 || filename[0] == '.' || - strchr(filename, '/') != NULL) { - /* unsafe characters found, bail out */ - tag_free(tag); - return NULL; + + struct song *song = cue_parser_get(playlist->parser); + if (song != NULL) + return song; + + const char *line; + while ((line = text_input_stream_read(playlist->tis)) != NULL) { + cue_parser_feed(playlist->parser, line); + song = cue_parser_get(playlist->parser); + if (song != NULL) + return song; } - song = song_remote_new(filename); - song->tag = tag; - song->start_ms = ((track_get_start(track) - + track_get_index(track, 1) - - track_get_zero_pre(track)) * 1000) / 75; - - /* append pregap of the next track to the end of this one */ - track = cd_get_track(playlist->cd, playlist->next); - if (track != NULL) - song->end_ms = ((track_get_start(track) - + track_get_index(track, 1) - - track_get_zero_pre(track)) * 1000) / 75; - else - song->end_ms = 0; - - return song; + cue_parser_finish(playlist->parser); + return cue_parser_get(playlist->parser); } static const char *const cue_playlist_suffixes[] = { @@ -132,7 +99,7 @@ static const char *const cue_playlist_mime_types[] = { const struct playlist_plugin cue_playlist_plugin = { .name = "cue", - .open_uri = cue_playlist_open_uri, + .open_stream = cue_playlist_open_stream, .close = cue_playlist_close, .read = cue_playlist_read, diff --git a/src/playlist_list.c b/src/playlist_list.c index 1f220eee..f89ab386 100644 --- a/src/playlist_list.c +++ b/src/playlist_list.c @@ -54,9 +54,7 @@ static const struct playlist_plugin *const playlist_plugins[] = { #ifdef ENABLE_LASTFM &lastfm_playlist_plugin, #endif -#ifdef HAVE_CUE &cue_playlist_plugin, -#endif #ifdef HAVE_FLAC &flac_playlist_plugin, #endif -- cgit v1.2.3