cue_parser: new line based CUE sheet parser
To replace libcue, the unmaintained and crashy library.
This commit is contained in:
		
							
								
								
									
										19
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								Makefile.am
									
									
									
									
									
								
							@@ -218,7 +218,6 @@ mpd_headers = \
 | 
				
			|||||||
	src/archive/iso9660_archive_plugin.h \
 | 
						src/archive/iso9660_archive_plugin.h \
 | 
				
			||||||
	src/archive/zzip_archive_plugin.h \
 | 
						src/archive/zzip_archive_plugin.h \
 | 
				
			||||||
	src/input/archive_input_plugin.h \
 | 
						src/input/archive_input_plugin.h \
 | 
				
			||||||
	src/cue/cue_tag.h\
 | 
					 | 
				
			||||||
	src/mpd_error.h
 | 
						src/mpd_error.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
src_mpd_SOURCES = \
 | 
					src_mpd_SOURCES = \
 | 
				
			||||||
@@ -239,6 +238,7 @@ src_mpd_SOURCES = \
 | 
				
			|||||||
	src/cmdline.c \
 | 
						src/cmdline.c \
 | 
				
			||||||
	src/conf.c \
 | 
						src/conf.c \
 | 
				
			||||||
	src/crossfade.c \
 | 
						src/crossfade.c \
 | 
				
			||||||
 | 
						src/cue/cue_parser.c src/cue/cue_parser.h \
 | 
				
			||||||
	src/dbUtils.c \
 | 
						src/dbUtils.c \
 | 
				
			||||||
	src/decoder_thread.c \
 | 
						src/decoder_thread.c \
 | 
				
			||||||
	src/decoder_control.c \
 | 
						src/decoder_control.c \
 | 
				
			||||||
@@ -478,8 +478,7 @@ libdecoder_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
 | 
				
			|||||||
	$(MPG123_CFLAGS) \
 | 
						$(MPG123_CFLAGS) \
 | 
				
			||||||
	$(FFMPEG_CFLAGS) \
 | 
						$(FFMPEG_CFLAGS) \
 | 
				
			||||||
	$(MPCDEC_CFLAGS) \
 | 
						$(MPCDEC_CFLAGS) \
 | 
				
			||||||
	$(FAAD_CFLAGS) \
 | 
						$(FAAD_CFLAGS)
 | 
				
			||||||
	$(CUE_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DECODER_LIBS = \
 | 
					DECODER_LIBS = \
 | 
				
			||||||
	libdecoder_plugins.a \
 | 
						libdecoder_plugins.a \
 | 
				
			||||||
@@ -497,8 +496,7 @@ DECODER_LIBS = \
 | 
				
			|||||||
	$(MP4FF_LIBS) \
 | 
						$(MP4FF_LIBS) \
 | 
				
			||||||
	$(FFMPEG_LIBS) \
 | 
						$(FFMPEG_LIBS) \
 | 
				
			||||||
	$(MPCDEC_LIBS) \
 | 
						$(MPCDEC_LIBS) \
 | 
				
			||||||
	$(FAAD_LIBS) \
 | 
						$(FAAD_LIBS)
 | 
				
			||||||
	$(CUE_LIBS)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DECODER_SRC =
 | 
					DECODER_SRC =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -858,10 +856,10 @@ libplaylist_plugins_a_SOURCES = \
 | 
				
			|||||||
	src/playlist/xspf_playlist_plugin.c \
 | 
						src/playlist/xspf_playlist_plugin.c \
 | 
				
			||||||
	src/playlist/asx_playlist_plugin.c \
 | 
						src/playlist/asx_playlist_plugin.c \
 | 
				
			||||||
	src/playlist/rss_playlist_plugin.c \
 | 
						src/playlist/rss_playlist_plugin.c \
 | 
				
			||||||
 | 
						src/playlist/cue_playlist_plugin.c \
 | 
				
			||||||
	src/playlist_list.c
 | 
						src/playlist_list.c
 | 
				
			||||||
libplaylist_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
 | 
					libplaylist_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
 | 
				
			||||||
	$(patsubst -I%/FLAC,-I%,$(FLAC_CFLAGS)) \
 | 
						$(patsubst -I%/FLAC,-I%,$(FLAC_CFLAGS))
 | 
				
			||||||
	$(CUE_CFLAGS)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
PLAYLIST_LIBS = \
 | 
					PLAYLIST_LIBS = \
 | 
				
			||||||
	libplaylist_plugins.a \
 | 
						libplaylist_plugins.a \
 | 
				
			||||||
@@ -875,11 +873,6 @@ if ENABLE_DESPOTIFY
 | 
				
			|||||||
libplaylist_plugins_a_SOURCES += src/playlist/despotify_playlist_plugin.c
 | 
					libplaylist_plugins_a_SOURCES += src/playlist/despotify_playlist_plugin.c
 | 
				
			||||||
endif
 | 
					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
 | 
					if HAVE_FLAC
 | 
				
			||||||
libplaylist_plugins_a_SOURCES += src/playlist/flac_playlist_plugin.c
 | 
					libplaylist_plugins_a_SOURCES += src/playlist/flac_playlist_plugin.c
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
@@ -998,7 +991,6 @@ test_run_input_SOURCES = test/run_input.c \
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
test_dump_playlist_LDADD = \
 | 
					test_dump_playlist_LDADD = \
 | 
				
			||||||
	$(PLAYLIST_LIBS) \
 | 
						$(PLAYLIST_LIBS) \
 | 
				
			||||||
	$(CUE_LIBS) \
 | 
					 | 
				
			||||||
	$(FLAC_LIBS) \
 | 
						$(FLAC_LIBS) \
 | 
				
			||||||
	$(INPUT_LIBS) \
 | 
						$(INPUT_LIBS) \
 | 
				
			||||||
	$(ARCHIVE_LIBS) \
 | 
						$(ARCHIVE_LIBS) \
 | 
				
			||||||
@@ -1009,6 +1001,7 @@ test_dump_playlist_SOURCES = test/dump_playlist.c \
 | 
				
			|||||||
	src/uri.c \
 | 
						src/uri.c \
 | 
				
			||||||
	src/song.c src/tag.c src/tag_pool.c src/tag_save.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/text_input_stream.c src/fifo_buffer.c \
 | 
				
			||||||
 | 
						src/cue/cue_parser.c src/cue/cue_parser.h \
 | 
				
			||||||
	src/fd_util.c
 | 
						src/fd_util.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if HAVE_FLAC
 | 
					if HAVE_FLAC
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								NEWS
									
									
									
									
									
								
							@@ -27,6 +27,7 @@ ver 0.17 (2011/??/??)
 | 
				
			|||||||
  - alsa: listen for external volume changes
 | 
					  - alsa: listen for external volume changes
 | 
				
			||||||
* playlist:
 | 
					* playlist:
 | 
				
			||||||
  - allow references to songs outside the music directory
 | 
					  - allow references to songs outside the music directory
 | 
				
			||||||
 | 
					  - new CUE parser, without libcue
 | 
				
			||||||
* state_file: add option "restore_paused"
 | 
					* state_file: add option "restore_paused"
 | 
				
			||||||
* cue: show CUE track numbers
 | 
					* cue: show CUE track numbers
 | 
				
			||||||
* allow port specification in "bind_to_address" settings
 | 
					* allow port specification in "bind_to_address" settings
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								configure.ac
									
									
									
									
									
								
							@@ -157,11 +157,6 @@ AC_ARG_ENABLE(cdio-paranoia,
 | 
				
			|||||||
		[enable support for audio CD support]),,
 | 
							[enable support for audio CD support]),,
 | 
				
			||||||
	enable_cdio_paranoia=auto)
 | 
						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,
 | 
					AC_ARG_ENABLE(curl,
 | 
				
			||||||
	AS_HELP_STRING([--enable-curl],
 | 
						AS_HELP_STRING([--enable-curl],
 | 
				
			||||||
		[enable support for libcurl HTTP streaming (default: auto)]),,
 | 
							[enable support for libcurl HTTP streaming (default: auto)]),,
 | 
				
			||||||
@@ -539,16 +534,6 @@ dnl ---------------------------------------------------------------------------
 | 
				
			|||||||
dnl Metadata Plugins
 | 
					dnl Metadata Plugins
 | 
				
			||||||
dnl ---------------------------------------------------------------------------
 | 
					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 --------------------------------
 | 
					dnl -------------------------------- libid3tag --------------------------------
 | 
				
			||||||
MPD_AUTO_PKG_LIB(id3, ID3TAG, id3tag, id3tag, id3_file_open, [-lid3tag -lz], [],
 | 
					MPD_AUTO_PKG_LIB(id3, ID3TAG, id3tag, id3tag, id3_file_open, [-lid3tag -lz], [],
 | 
				
			||||||
	[id3tag], [libid3tag not found])
 | 
						[id3tag], [libid3tag not found])
 | 
				
			||||||
@@ -686,7 +671,7 @@ if test x$enable_despotify = xyes; then
 | 
				
			|||||||
fi
 | 
					fi
 | 
				
			||||||
AM_CONDITIONAL(ENABLE_DESPOTIFY, test x$enable_despotify = xyes)
 | 
					AM_CONDITIONAL(ENABLE_DESPOTIFY, test x$enable_despotify = xyes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dnl ---------------------------------- libcue ---------------------------------
 | 
					dnl ---------------------------------- cdio ---------------------------------
 | 
				
			||||||
MPD_AUTO_PKG(cdio_paranoia, CDIO_PARANOIA, [libcdio_paranoia],
 | 
					MPD_AUTO_PKG(cdio_paranoia, CDIO_PARANOIA, [libcdio_paranoia],
 | 
				
			||||||
	[libcdio_paranoia audio CD library], [libcdio_paranoia not found])
 | 
						[libcdio_paranoia audio CD library], [libcdio_paranoia not found])
 | 
				
			||||||
if test x$enable_cdio_paranoia = xyes; then
 | 
					if test x$enable_cdio_paranoia = xyes; then
 | 
				
			||||||
@@ -1547,7 +1532,6 @@ results(inotify, [inotify])
 | 
				
			|||||||
results(sqlite, [SQLite])
 | 
					results(sqlite, [SQLite])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
printf '\nMetadata support:\n\t'
 | 
					printf '\nMetadata support:\n\t'
 | 
				
			||||||
results(cue,[cue])
 | 
					 | 
				
			||||||
results(id3,[ID3])
 | 
					results(id3,[ID3])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
printf '\nPlayback support:\n\t'
 | 
					printf '\nPlayback support:\n\t'
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										327
									
								
								src/cue/cue_parser.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								src/cue/cue_parser.c
									
									
									
									
									
										Normal file
									
								
							@@ -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 <assert.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										58
									
								
								src/cue/cue_parser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/cue/cue_parser.h
									
									
									
									
									
										Normal file
									
								
							@@ -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 <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
@@ -1,244 +0,0 @@
 | 
				
			|||||||
#include "config.h"
 | 
					 | 
				
			||||||
#include "cue_tag.h"
 | 
					 | 
				
			||||||
#include "tag.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <libcue/libcue.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,23 +0,0 @@
 | 
				
			|||||||
#ifndef MPD_CUE_TAG_H
 | 
					 | 
				
			||||||
#define MPD_CUE_TAG_H
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "check.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef HAVE_CUE /* libcue */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
@@ -22,10 +22,11 @@
 | 
				
			|||||||
#include "playlist_plugin.h"
 | 
					#include "playlist_plugin.h"
 | 
				
			||||||
#include "tag.h"
 | 
					#include "tag.h"
 | 
				
			||||||
#include "song.h"
 | 
					#include "song.h"
 | 
				
			||||||
#include "cue/cue_tag.h"
 | 
					#include "cue/cue_parser.h"
 | 
				
			||||||
 | 
					#include "input_stream.h"
 | 
				
			||||||
 | 
					#include "text_input_stream.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <glib.h>
 | 
					#include <glib.h>
 | 
				
			||||||
#include <libcue/libcue.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,32 +36,21 @@
 | 
				
			|||||||
struct cue_playlist {
 | 
					struct cue_playlist {
 | 
				
			||||||
	struct playlist_provider base;
 | 
						struct playlist_provider base;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct Cd *cd;
 | 
						struct input_stream *is;
 | 
				
			||||||
 | 
						struct text_input_stream *tis;
 | 
				
			||||||
	unsigned next;
 | 
						struct cue_parser *parser;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct playlist_provider *
 | 
					static struct playlist_provider *
 | 
				
			||||||
cue_playlist_open_uri(const char *uri,
 | 
					cue_playlist_open_stream(struct input_stream *is)
 | 
				
			||||||
		      G_GNUC_UNUSED GMutex *mutex, G_GNUC_UNUSED GCond *cond)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cue_playlist *playlist;
 | 
						struct cue_playlist *playlist = g_new(struct cue_playlist, 1);
 | 
				
			||||||
	FILE *file;
 | 
					 | 
				
			||||||
	struct Cd *cd;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	file = fopen(uri, "rt");
 | 
					 | 
				
			||||||
	if (file == NULL)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cd = cue_parse_file(file);
 | 
					 | 
				
			||||||
	fclose(file);
 | 
					 | 
				
			||||||
	if (cd == NULL)
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	playlist = g_new(struct cue_playlist, 1);
 | 
					 | 
				
			||||||
	playlist_provider_init(&playlist->base, &cue_playlist_plugin);
 | 
						playlist_provider_init(&playlist->base, &cue_playlist_plugin);
 | 
				
			||||||
	playlist->cd = cd;
 | 
					
 | 
				
			||||||
	playlist->next = 1;
 | 
						playlist->is = is;
 | 
				
			||||||
 | 
						playlist->tis = text_input_stream_new(is);
 | 
				
			||||||
 | 
						playlist->parser = cue_parser_new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &playlist->base;
 | 
						return &playlist->base;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -70,7 +60,8 @@ cue_playlist_close(struct playlist_provider *_playlist)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct cue_playlist *playlist = (struct cue_playlist *)_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);
 | 
						g_free(playlist);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,45 +69,21 @@ static struct song *
 | 
				
			|||||||
cue_playlist_read(struct playlist_provider *_playlist)
 | 
					cue_playlist_read(struct playlist_provider *_playlist)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cue_playlist *playlist = (struct cue_playlist *)_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);
 | 
						struct song *song = cue_parser_get(playlist->parser);
 | 
				
			||||||
	if (track == NULL)
 | 
						if (song != NULL)
 | 
				
			||||||
		return NULL;
 | 
							return song;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tag = cue_tag(playlist->cd, playlist->next);
 | 
						const char *line;
 | 
				
			||||||
	if (tag == NULL)
 | 
						while ((line = text_input_stream_read(playlist->tis)) != NULL) {
 | 
				
			||||||
		return NULL;
 | 
							cue_parser_feed(playlist->parser, line);
 | 
				
			||||||
 | 
							song = cue_parser_get(playlist->parser);
 | 
				
			||||||
	++playlist->next;
 | 
							if (song != NULL)
 | 
				
			||||||
 | 
								return song;
 | 
				
			||||||
	filename = track_get_filename(track);
 | 
					 | 
				
			||||||
	if (*filename == 0 || filename[0] == '.' ||
 | 
					 | 
				
			||||||
	    strchr(filename, '/') != NULL) {
 | 
					 | 
				
			||||||
		/* unsafe characters found, bail out */
 | 
					 | 
				
			||||||
		tag_free(tag);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	song = song_remote_new(filename);
 | 
						cue_parser_finish(playlist->parser);
 | 
				
			||||||
	song->tag = tag;
 | 
						return cue_parser_get(playlist->parser);
 | 
				
			||||||
	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;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *const cue_playlist_suffixes[] = {
 | 
					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 = {
 | 
					const struct playlist_plugin cue_playlist_plugin = {
 | 
				
			||||||
	.name = "cue",
 | 
						.name = "cue",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.open_uri = cue_playlist_open_uri,
 | 
						.open_stream = cue_playlist_open_stream,
 | 
				
			||||||
	.close = cue_playlist_close,
 | 
						.close = cue_playlist_close,
 | 
				
			||||||
	.read = cue_playlist_read,
 | 
						.read = cue_playlist_read,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,9 +54,7 @@ static const struct playlist_plugin *const playlist_plugins[] = {
 | 
				
			|||||||
#ifdef ENABLE_LASTFM
 | 
					#ifdef ENABLE_LASTFM
 | 
				
			||||||
	&lastfm_playlist_plugin,
 | 
						&lastfm_playlist_plugin,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef HAVE_CUE
 | 
					 | 
				
			||||||
	&cue_playlist_plugin,
 | 
						&cue_playlist_plugin,
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef HAVE_FLAC
 | 
					#ifdef HAVE_FLAC
 | 
				
			||||||
	&flac_playlist_plugin,
 | 
						&flac_playlist_plugin,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user