From b715e522cff7109c370e66d29ba22340c9259c52 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 2 Jan 2013 19:52:57 +0100 Subject: db_save, state_file: convert to C++ --- Makefile.am | 58 ++++----- src/DatabaseGlue.cxx | 2 +- src/DatabaseSave.cxx | 182 ++++++++++++++++++++++++++++ src/DatabaseSave.hxx | 35 ++++++ src/DirectorySave.cxx | 188 +++++++++++++++++++++++++++++ src/DirectorySave.hxx | 36 ++++++ src/Main.cxx | 2 +- src/OutputState.cxx | 94 +++++++++++++++ src/OutputState.hxx | 44 +++++++ src/PlaylistDatabase.cxx | 82 +++++++++++++ src/PlaylistDatabase.hxx | 39 ++++++ src/PlaylistSave.hxx | 1 - src/PlaylistState.cxx | 252 +++++++++++++++++++++++++++++++++++++++ src/PlaylistState.hxx | 52 ++++++++ src/QueueSave.cxx | 129 ++++++++++++++++++++ src/QueueSave.hxx | 43 +++++++ src/SongSave.cxx | 136 +++++++++++++++++++++ src/SongSave.hxx | 47 ++++++++ src/StateFile.cxx | 165 ++++++++++++++++++++++++++ src/StateFile.hxx | 33 ++++++ src/TagSave.cxx | 38 ++++++ src/TagSave.hxx | 29 +++++ src/db/SimpleDatabasePlugin.cxx | 2 +- src/db_save.c | 179 ---------------------------- src/db_save.h | 36 ------ src/directory_save.c | 185 ----------------------------- src/directory_save.h | 37 ------ src/output_state.c | 91 -------------- src/output_state.h | 45 ------- src/playlist_database.c | 79 ------------- src/playlist_database.h | 40 ------- src/playlist_global.c | 1 - src/playlist_state.c | 250 --------------------------------------- src/playlist_state.h | 53 --------- src/queue_save.c | 126 -------------------- src/queue_save.h | 43 ------- src/song_save.c | 133 --------------------- src/song_save.h | 47 -------- src/state_file.c | 162 ------------------------- src/state_file.h | 33 ------ src/tag_save.c | 38 ------ src/tag_save.h | 29 ----- test/DumpPlaylist.cxx | 255 ++++++++++++++++++++++++++++++++++++++++ test/RunInput.cxx | 186 +++++++++++++++++++++++++++++ test/dump_playlist.c | 252 --------------------------------------- test/run_input.c | 183 ---------------------------- 46 files changed, 2093 insertions(+), 2079 deletions(-) create mode 100644 src/DatabaseSave.cxx create mode 100644 src/DatabaseSave.hxx create mode 100644 src/DirectorySave.cxx create mode 100644 src/DirectorySave.hxx create mode 100644 src/OutputState.cxx create mode 100644 src/OutputState.hxx create mode 100644 src/PlaylistDatabase.cxx create mode 100644 src/PlaylistDatabase.hxx create mode 100644 src/PlaylistState.cxx create mode 100644 src/PlaylistState.hxx create mode 100644 src/QueueSave.cxx create mode 100644 src/QueueSave.hxx create mode 100644 src/SongSave.cxx create mode 100644 src/SongSave.hxx create mode 100644 src/StateFile.cxx create mode 100644 src/StateFile.hxx create mode 100644 src/TagSave.cxx create mode 100644 src/TagSave.hxx delete mode 100644 src/db_save.c delete mode 100644 src/db_save.h delete mode 100644 src/directory_save.c delete mode 100644 src/directory_save.h delete mode 100644 src/output_state.c delete mode 100644 src/output_state.h delete mode 100644 src/playlist_database.c delete mode 100644 src/playlist_database.h delete mode 100644 src/playlist_state.c delete mode 100644 src/playlist_state.h delete mode 100644 src/queue_save.c delete mode 100644 src/queue_save.h delete mode 100644 src/song_save.c delete mode 100644 src/song_save.h delete mode 100644 src/state_file.c delete mode 100644 src/state_file.h delete mode 100644 src/tag_save.c delete mode 100644 src/tag_save.h create mode 100644 test/DumpPlaylist.cxx create mode 100644 test/RunInput.cxx delete mode 100644 test/dump_playlist.c delete mode 100644 test/run_input.c diff --git a/Makefile.am b/Makefile.am index 5bfabe752..137a567c5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,7 +56,6 @@ mpd_headers = \ src/output_all.h \ src/output_thread.h \ src/output_control.h \ - src/output_state.h \ src/output_print.h \ src/output_command.h \ src/filter_internal.h \ @@ -82,7 +81,6 @@ mpd_headers = \ src/decoder_plugin.h \ src/decoder_internal.h \ src/directory.h \ - src/directory_save.h \ src/database.h \ src/encoder_plugin.h \ src/encoder_list.h \ @@ -144,11 +142,9 @@ mpd_headers = \ src/playlist.h \ src/playlist_error.h \ src/playlist_internal.h \ - src/playlist_state.h \ src/playlist_plugin.h \ src/playlist_list.h \ src/playlist_vector.h \ - src/playlist_database.h \ src/playlist/extm3u_playlist_plugin.h \ src/playlist/m3u_playlist_plugin.h \ src/playlist/pls_playlist_plugin.h \ @@ -162,7 +158,6 @@ mpd_headers = \ src/riff.h \ src/aiff.h \ src/queue.h \ - src/queue_save.h \ src/refcount.h \ src/replay_gain_config.h \ src/replay_gain_info.h \ @@ -171,11 +166,9 @@ mpd_headers = \ src/time_print.c src/time_print.h \ src/song.h \ src/song_print.h \ - src/song_save.h \ src/song_sticker.h \ src/song_sort.c src/song_sort.h \ src/socket_util.h \ - src/state_file.h \ src/stats.h \ src/sticker.h \ src/sticker_print.h \ @@ -187,7 +180,6 @@ mpd_headers = \ src/tag_id3.h \ src/tag_rva2.h \ src/tag_print.h \ - src/tag_save.h \ src/tokenizer.h \ src/strset.h \ src/uri.h \ @@ -241,14 +233,14 @@ src_mpd_SOURCES = \ src/decoder_internal.c \ src/decoder_print.c \ src/Directory.cxx \ - src/directory_save.c \ + src/DirectorySave.cxx src/DirectorySave.hxx \ src/DatabaseGlue.cxx \ src/DatabasePrint.cxx src/DatabasePrint.hxx \ src/DatabaseQueue.cxx src/DatabaseQueue.hxx \ src/DatabasePlaylist.cxx src/DatabasePlaylist.hxx \ src/db_error.h \ src/db_lock.c src/db_lock.h \ - src/db_save.c src/db_save.h \ + src/DatabaseSave.cxx src/DatabaseSave.hxx \ src/DatabasePlugin.hxx \ src/DatabaseVisitor.hxx \ src/DatabaseSelection.cxx src/DatabaseSelection.hxx \ @@ -313,28 +305,28 @@ src_mpd_SOURCES = \ src/PlaylistMapper.cxx src/PlaylistMapper.hxx \ src/PlaylistAny.cxx src/PlaylistAny.hxx \ src/PlaylistSong.cxx src/PlaylistSong.hxx \ - src/playlist_state.c \ + src/PlaylistState.cxx src/PlaylistState.hxx \ src/PlaylistQueue.cxx src/PlaylistQueue.hxx \ src/playlist_vector.c \ - src/playlist_database.c \ + src/PlaylistDatabase.cxx \ src/queue.c \ src/QueuePrint.cxx src/QueuePrint.hxx \ - src/queue_save.c \ + src/QueueSave.cxx src/QueueSave.hxx \ src/replay_gain_config.c \ src/replay_gain_info.c \ src/sig_handlers.c \ src/Song.cxx \ src/song_update.c \ src/song_print.c \ - src/song_save.c \ + src/SongSave.cxx src/SongSave.hxx \ src/resolver.c src/resolver.h \ src/socket_util.c \ - src/state_file.c \ + src/StateFile.cxx src/StateFile.hxx \ src/Stats.cxx \ src/tag.c \ src/tag_pool.c \ src/tag_print.c \ - src/tag_save.c \ + src/TagSave.cxx src/TagSave.hxx \ src/tag_handler.c src/tag_handler.h \ src/tag_file.c src/tag_file.h \ src/tokenizer.c \ @@ -821,7 +813,7 @@ OUTPUT_API_SRC = \ src/output_thread.c \ src/output_error.h \ src/output_control.c \ - src/output_state.c \ + src/OutputState.cxx src/OutputState.hxx \ src/output_print.c \ src/output_command.c \ src/output_plugin.c src/output_plugin.h \ @@ -1046,9 +1038,9 @@ noinst_PROGRAMS = \ test/read_conf \ test/run_resolver \ test/DumpDatabase \ - test/run_input \ + test/RunInput \ test/dump_text_file \ - test/dump_playlist \ + test/DumpPlaylist \ test/run_decoder \ test/read_tags \ test/run_filter \ @@ -1083,25 +1075,25 @@ test_DumpDatabase_LDADD = \ test_DumpDatabase_SOURCES = test/DumpDatabase.cxx \ src/DatabaseRegistry.cxx \ src/DatabaseSelection.cxx \ - src/Directory.cxx src/directory_save.c \ - src/playlist_vector.c src/playlist_database.c \ - src/db_lock.c src/db_save.c \ - src/Song.cxx src/song_sort.c src/song_save.c \ - src/tag.c src/tag_pool.c src/tag_save.c \ + src/Directory.cxx src/DirectorySave.cxx \ + src/playlist_vector.c src/PlaylistDatabase.cxx \ + src/db_lock.c src/DatabaseSave.cxx \ + src/Song.cxx src/song_sort.c src/SongSave.cxx \ + src/tag.c src/tag_pool.c src/TagSave.cxx \ src/path.c \ src/SongFilter.cxx \ src/text_file.c \ src/conf.c src/tokenizer.c src/utils.c src/string_util.c -test_run_input_LDADD = \ +test_RunInput_LDADD = \ $(INPUT_LIBS) \ $(ARCHIVE_LIBS) \ $(GLIB_LIBS) -test_run_input_SOURCES = test/run_input.c \ +test_RunInput_SOURCES = test/RunInput.c \ test/stdbin.h \ src/io_thread.c src/io_thread.h \ src/conf.c src/tokenizer.c src/utils.c src/string_util.c\ - src/tag.c src/tag_pool.c src/tag_save.c \ + src/tag.c src/tag_pool.c src/TagSave.cxx \ src/fd_util.c test_dump_text_file_LDADD = \ @@ -1116,7 +1108,7 @@ test_dump_text_file_SOURCES = test/dump_text_file.c \ src/text_input_stream.c src/fifo_buffer.c \ src/fd_util.c -test_dump_playlist_LDADD = \ +test_DumpPlaylist_LDADD = \ $(PLAYLIST_LIBS) \ $(FLAC_LIBS) \ $(INPUT_LIBS) \ @@ -1125,12 +1117,12 @@ test_dump_playlist_LDADD = \ $(TAG_LIBS) \ libutil.a \ $(GLIB_LIBS) -test_dump_playlist_SOURCES = test/dump_playlist.c \ +test_DumpPlaylist_SOURCES = test/DumpPlaylist.cxx \ $(DECODER_SRC) \ src/io_thread.c src/io_thread.h \ src/conf.c src/tokenizer.c src/utils.c src/string_util.c\ src/uri.c \ - src/Song.cxx src/tag.c src/tag_pool.c src/tag_save.c \ + src/Song.cxx src/tag.c src/tag_pool.c src/TagSave.cxx \ src/tag_handler.c src/tag_file.c \ src/audio_check.c src/pcm_buffer.c \ src/text_input_stream.c src/fifo_buffer.c \ @@ -1138,7 +1130,7 @@ test_dump_playlist_SOURCES = test/dump_playlist.c \ src/fd_util.c if HAVE_FLAC -test_dump_playlist_SOURCES += \ +test_DumpPlaylist_SOURCES += \ src/replay_gain_info.c \ src/decoder/FLACMetaData.cxx endif @@ -1213,11 +1205,11 @@ test_run_filter_SOURCES = test/run_filter.c \ if ENABLE_DESPOTIFY test_read_tags_SOURCES += \ src/despotify_utils.c -test_run_input_SOURCES += \ +test_RunInput_SOURCES += \ src/despotify_utils.c test_dump_text_file_SOURCES += \ src/despotify_utils.c -test_dump_playlist_SOURCES += \ +test_DumpPlaylist_SOURCES += \ src/despotify_utils.c test_run_decoder_SOURCES += \ src/despotify_utils.c diff --git a/src/DatabaseGlue.cxx b/src/DatabaseGlue.cxx index 03a717cb2..88791879e 100644 --- a/src/DatabaseGlue.cxx +++ b/src/DatabaseGlue.cxx @@ -20,11 +20,11 @@ #include "config.h" #include "DatabaseGlue.hxx" #include "DatabaseRegistry.hxx" +#include "DatabaseSave.hxx" extern "C" { #include "database.h" #include "db_error.h" -#include "db_save.h" #include "stats.h" #include "conf.h" #include "glib_compat.h" diff --git a/src/DatabaseSave.cxx b/src/DatabaseSave.cxx new file mode 100644 index 000000000..711d5b2f3 --- /dev/null +++ b/src/DatabaseSave.cxx @@ -0,0 +1,182 @@ +/* + * 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 "DatabaseSave.hxx" +#include "db_lock.h" +#include "directory.h" +#include "DirectorySave.hxx" +#include "song.h" + +extern "C" { +#include "path.h" +#include "text_file.h" +#include "tag.h" +#include "tag_internal.h" +} + +#include + +#include +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "database" + +#define DIRECTORY_INFO_BEGIN "info_begin" +#define DIRECTORY_INFO_END "info_end" +#define DB_FORMAT_PREFIX "format: " +#define DIRECTORY_MPD_VERSION "mpd_version: " +#define DIRECTORY_FS_CHARSET "fs_charset: " +#define DB_TAG_PREFIX "tag: " + +enum { + DB_FORMAT = 1, +}; + +G_GNUC_CONST +static GQuark +db_quark(void) +{ + return g_quark_from_static_string("database"); +} + +void +db_save_internal(FILE *fp, const struct directory *music_root) +{ + assert(music_root != NULL); + + fprintf(fp, "%s\n", DIRECTORY_INFO_BEGIN); + fprintf(fp, DB_FORMAT_PREFIX "%u\n", DB_FORMAT); + fprintf(fp, "%s%s\n", DIRECTORY_MPD_VERSION, VERSION); + fprintf(fp, "%s%s\n", DIRECTORY_FS_CHARSET, path_get_fs_charset()); + + for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) + if (!ignore_tag_items[i]) + fprintf(fp, DB_TAG_PREFIX "%s\n", tag_item_names[i]); + + fprintf(fp, "%s\n", DIRECTORY_INFO_END); + + directory_save(fp, music_root); +} + +bool +db_load_internal(FILE *fp, struct directory *music_root, GError **error) +{ + GString *buffer = g_string_sized_new(1024); + char *line; + int format = 0; + bool found_charset = false, found_version = false; + bool success; + bool tags[TAG_NUM_OF_ITEM_TYPES]; + + assert(music_root != NULL); + + /* get initial info */ + line = read_text_line(fp, buffer); + if (line == NULL || strcmp(DIRECTORY_INFO_BEGIN, line) != 0) { + g_set_error(error, db_quark(), 0, "Database corrupted"); + g_string_free(buffer, true); + return false; + } + + memset(tags, false, sizeof(tags)); + + while ((line = read_text_line(fp, buffer)) != NULL && + strcmp(line, DIRECTORY_INFO_END) != 0) { + if (g_str_has_prefix(line, DB_FORMAT_PREFIX)) { + format = atoi(line + sizeof(DB_FORMAT_PREFIX) - 1); + } else if (g_str_has_prefix(line, DIRECTORY_MPD_VERSION)) { + if (found_version) { + g_set_error(error, db_quark(), 0, + "Duplicate version line"); + g_string_free(buffer, true); + return false; + } + + found_version = true; + } else if (g_str_has_prefix(line, DIRECTORY_FS_CHARSET)) { + const char *new_charset, *old_charset; + + if (found_charset) { + g_set_error(error, db_quark(), 0, + "Duplicate charset line"); + g_string_free(buffer, true); + return false; + } + + found_charset = true; + + new_charset = line + sizeof(DIRECTORY_FS_CHARSET) - 1; + old_charset = path_get_fs_charset(); + if (old_charset != NULL + && strcmp(new_charset, old_charset)) { + g_set_error(error, db_quark(), 0, + "Existing database has charset " + "\"%s\" instead of \"%s\"; " + "discarding database file", + new_charset, old_charset); + g_string_free(buffer, true); + return false; + } + } else if (g_str_has_prefix(line, DB_TAG_PREFIX)) { + const char *name = line + sizeof(DB_TAG_PREFIX) - 1; + enum tag_type tag = tag_name_parse(name); + if (tag == TAG_NUM_OF_ITEM_TYPES) { + g_set_error(error, db_quark(), 0, + "Unrecognized tag '%s', " + "discarding database file", + name); + return false; + } + + tags[tag] = true; + } else { + g_set_error(error, db_quark(), 0, + "Malformed line: %s", line); + g_string_free(buffer, true); + return false; + } + } + + if (format != DB_FORMAT) { + g_set_error(error, db_quark(), 0, + "Database format mismatch, " + "discarding database file"); + return false; + } + + for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) { + if (!ignore_tag_items[i] && !tags[i]) { + g_set_error(error, db_quark(), 0, + "Tag list mismatch, " + "discarding database file"); + return false; + } + } + + g_debug("reading DB"); + + db_lock(); + success = directory_load(fp, music_root, buffer, error); + db_unlock(); + g_string_free(buffer, true); + + return success; +} diff --git a/src/DatabaseSave.hxx b/src/DatabaseSave.hxx new file mode 100644 index 000000000..f96bf5e21 --- /dev/null +++ b/src/DatabaseSave.hxx @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2003-2013 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_DATABASE_SAVE_HXX +#define MPD_DATABASE_SAVE_HXX + +#include "gerror.h" + +#include + +struct directory; + +void +db_save_internal(FILE *file, const struct directory *root); + +bool +db_load_internal(FILE *file, struct directory *root, GError **error); + +#endif diff --git a/src/DirectorySave.cxx b/src/DirectorySave.cxx new file mode 100644 index 000000000..83a1ffd5a --- /dev/null +++ b/src/DirectorySave.cxx @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2003-2013 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 "DirectorySave.hxx" +#include "directory.h" +#include "song.h" +#include "SongSave.hxx" +#include "PlaylistDatabase.hxx" + +extern "C" { +#include "text_file.h" +} + +#include +#include + +#define DIRECTORY_DIR "directory: " +#define DIRECTORY_MTIME "mtime: " +#define DIRECTORY_BEGIN "begin: " +#define DIRECTORY_END "end: " + +/** + * The quark used for GError.domain. + */ +static inline GQuark +directory_quark(void) +{ + return g_quark_from_static_string("directory"); +} + +void +directory_save(FILE *fp, const struct directory *directory) +{ + if (!directory_is_root(directory)) { + fprintf(fp, DIRECTORY_MTIME "%lu\n", + (unsigned long)directory->mtime); + + fprintf(fp, "%s%s\n", DIRECTORY_BEGIN, + directory_get_path(directory)); + } + + struct directory *cur; + directory_for_each_child(cur, directory) { + char *base = g_path_get_basename(cur->path); + + fprintf(fp, DIRECTORY_DIR "%s\n", base); + g_free(base); + + directory_save(fp, cur); + + if (ferror(fp)) + return; + } + + struct song *song; + directory_for_each_song(song, directory) + song_save(fp, song); + + playlist_vector_save(fp, &directory->playlists); + + if (!directory_is_root(directory)) + fprintf(fp, DIRECTORY_END "%s\n", + directory_get_path(directory)); +} + +static struct directory * +directory_load_subdir(FILE *fp, struct directory *parent, const char *name, + GString *buffer, GError **error_r) +{ + const char *line; + bool success; + + if (directory_get_child(parent, name) != NULL) { + g_set_error(error_r, directory_quark(), 0, + "Duplicate subdirectory '%s'", name); + return NULL; + } + + struct directory *directory = directory_new_child(parent, name); + + line = read_text_line(fp, buffer); + if (line == NULL) { + g_set_error(error_r, directory_quark(), 0, + "Unexpected end of file"); + directory_delete(directory); + return NULL; + } + + if (g_str_has_prefix(line, DIRECTORY_MTIME)) { + directory->mtime = + g_ascii_strtoull(line + sizeof(DIRECTORY_MTIME) - 1, + NULL, 10); + + line = read_text_line(fp, buffer); + if (line == NULL) { + g_set_error(error_r, directory_quark(), 0, + "Unexpected end of file"); + directory_delete(directory); + return NULL; + } + } + + if (!g_str_has_prefix(line, DIRECTORY_BEGIN)) { + g_set_error(error_r, directory_quark(), 0, + "Malformed line: %s", line); + directory_delete(directory); + return NULL; + } + + success = directory_load(fp, directory, buffer, error_r); + if (!success) { + directory_delete(directory); + return NULL; + } + + return directory; +} + +bool +directory_load(FILE *fp, struct directory *directory, + GString *buffer, GError **error) +{ + const char *line; + + while ((line = read_text_line(fp, buffer)) != NULL && + !g_str_has_prefix(line, DIRECTORY_END)) { + if (g_str_has_prefix(line, DIRECTORY_DIR)) { + struct directory *subdir = + directory_load_subdir(fp, directory, + line + sizeof(DIRECTORY_DIR) - 1, + buffer, error); + if (subdir == NULL) + return false; + } else if (g_str_has_prefix(line, SONG_BEGIN)) { + const char *name = line + sizeof(SONG_BEGIN) - 1; + struct song *song; + + if (directory_get_song(directory, name) != NULL) { + g_set_error(error, directory_quark(), 0, + "Duplicate song '%s'", name); + return false; + } + + song = song_load(fp, directory, name, + buffer, error); + if (song == NULL) + return false; + + directory_add_song(directory, song); + } else if (g_str_has_prefix(line, PLAYLIST_META_BEGIN)) { + /* duplicate the name, because + playlist_metadata_load() will overwrite the + buffer */ + char *name = g_strdup(line + sizeof(PLAYLIST_META_BEGIN) - 1); + + if (!playlist_metadata_load(fp, &directory->playlists, + name, buffer, error)) { + g_free(name); + return false; + } + + g_free(name); + } else { + g_set_error(error, directory_quark(), 0, + "Malformed line: %s", line); + return false; + } + } + + return true; +} diff --git a/src/DirectorySave.hxx b/src/DirectorySave.hxx new file mode 100644 index 000000000..18c3bf64e --- /dev/null +++ b/src/DirectorySave.hxx @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2003-2013 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_DIRECTORY_SAVE_HXX +#define MPD_DIRECTORY_SAVE_HXX + +#include + +#include + +struct directory; + +void +directory_save(FILE *fp, const struct directory *directory); + +bool +directory_load(FILE *fp, struct directory *directory, + GString *buffer, GError **error); + +#endif diff --git a/src/Main.cxx b/src/Main.cxx index 44042d8ca..9a5fa1cd9 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -22,6 +22,7 @@ #include "PlaylistFile.hxx" #include "UpdateGlue.hxx" #include "chunk.h" +#include "StateFile.hxx" extern "C" { #include "daemon.h" @@ -51,7 +52,6 @@ extern "C" { #include "decoder_list.h" #include "input_init.h" #include "playlist_list.h" -#include "state_file.h" #include "tag.h" #include "zeroconf.h" #include "event_pipe.h" diff --git a/src/OutputState.cxx b/src/OutputState.cxx new file mode 100644 index 000000000..95aeacbca --- /dev/null +++ b/src/OutputState.cxx @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2003-2013 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. + */ + +/* + * Saving and loading the audio output states to/from the state file. + * + */ + +#include "config.h" +#include "OutputState.hxx" +#include "output_internal.h" + +extern "C" { +#include "output_all.h" +} + +#include + +#include +#include +#include + +#define AUDIO_DEVICE_STATE "audio_device_state:" + +unsigned audio_output_state_version; + +void +audio_output_state_save(FILE *fp) +{ + unsigned n = audio_output_count(); + + assert(n > 0); + + for (unsigned i = 0; i < n; ++i) { + const struct audio_output *ao = audio_output_get(i); + + fprintf(fp, AUDIO_DEVICE_STATE "%d:%s\n", + ao->enabled, ao->name); + } +} + +bool +audio_output_state_read(const char *line) +{ + long value; + char *endptr; + const char *name; + struct audio_output *ao; + + if (!g_str_has_prefix(line, AUDIO_DEVICE_STATE)) + return false; + + line += sizeof(AUDIO_DEVICE_STATE) - 1; + + value = strtol(line, &endptr, 10); + if (*endptr != ':' || (value != 0 && value != 1)) + return false; + + if (value != 0) + /* state is "enabled": no-op */ + return true; + + name = endptr + 1; + ao = audio_output_find(name); + if (ao == NULL) { + g_debug("Ignoring device state for '%s'", name); + return true; + } + + ao->enabled = false; + return true; +} + +unsigned +audio_output_state_get_version(void) +{ + return audio_output_state_version; +} diff --git a/src/OutputState.hxx b/src/OutputState.hxx new file mode 100644 index 000000000..5ab765ba8 --- /dev/null +++ b/src/OutputState.hxx @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2003-2013 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. + */ + +/* + * Saving and loading the audio output states to/from the state file. + * + */ + +#ifndef MPD_OUTPUT_STATE_HXX +#define MPD_OUTPUT_STATE_HXX + +#include + +bool +audio_output_state_read(const char *line); + +void +audio_output_state_save(FILE *fp); + +/** + * Generates a version number for the current state of the audio + * outputs. This is used by timer_save_state_file() to determine + * whether the state has changed and the state file should be saved. + */ +unsigned +audio_output_state_get_version(void); + +#endif diff --git a/src/PlaylistDatabase.cxx b/src/PlaylistDatabase.cxx new file mode 100644 index 000000000..b88ebbd6b --- /dev/null +++ b/src/PlaylistDatabase.cxx @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2003-2013 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 "PlaylistDatabase.hxx" + +extern "C" { +#include "playlist_vector.h" +#include "text_file.h" +#include "string_util.h" +} + +#include +#include + +static GQuark +playlist_database_quark(void) +{ + return g_quark_from_static_string("playlist_database"); +} + +void +playlist_vector_save(FILE *fp, const struct list_head *pv) +{ + struct playlist_metadata *pm; + playlist_vector_for_each(pm, pv) + fprintf(fp, PLAYLIST_META_BEGIN "%s\n" + "mtime: %li\n" + "playlist_end\n", + pm->name, (long)pm->mtime); +} + +bool +playlist_metadata_load(FILE *fp, struct list_head *pv, const char *name, + GString *buffer, GError **error_r) +{ + struct playlist_metadata pm; + pm.mtime = 0; + + char *line, *colon; + const char *value; + + while ((line = read_text_line(fp, buffer)) != NULL && + strcmp(line, "playlist_end") != 0) { + colon = strchr(line, ':'); + if (colon == NULL || colon == line) { + g_set_error(error_r, playlist_database_quark(), 0, + "unknown line in db: %s", line); + return false; + } + + *colon++ = 0; + value = strchug_fast_c(colon); + + if (strcmp(line, "mtime") == 0) + pm.mtime = strtol(value, NULL, 10); + else { + g_set_error(error_r, playlist_database_quark(), 0, + "unknown line in db: %s", line); + return false; + } + } + + playlist_vector_update_or_add(pv, name, pm.mtime); + return true; +} diff --git a/src/PlaylistDatabase.hxx b/src/PlaylistDatabase.hxx new file mode 100644 index 000000000..0b4cd3f3a --- /dev/null +++ b/src/PlaylistDatabase.hxx @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2003-2013 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_PLAYLIST_DATABASE_HXX +#define MPD_PLAYLIST_DATABASE_HXX + +#include "check.h" + +#include +#include + +#define PLAYLIST_META_BEGIN "playlist_begin: " + +struct list_head; + +void +playlist_vector_save(FILE *fp, const struct list_head *pv); + +bool +playlist_metadata_load(FILE *fp, struct list_head *pv, const char *name, + GString *buffer, GError **error_r); + +#endif diff --git a/src/PlaylistSave.hxx b/src/PlaylistSave.hxx index 20b2ca425..ff5f0c494 100644 --- a/src/PlaylistSave.hxx +++ b/src/PlaylistSave.hxx @@ -22,7 +22,6 @@ #include "playlist_error.h" -#include #include struct song; diff --git a/src/PlaylistState.cxx b/src/PlaylistState.cxx new file mode 100644 index 000000000..0cfd32723 --- /dev/null +++ b/src/PlaylistState.cxx @@ -0,0 +1,252 @@ +/* + * 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. + */ + +/* + * Saving and loading the playlist to/from the state file. + * + */ + +#include "config.h" +#include "PlaylistState.hxx" +#include "QueueSave.hxx" + +extern "C" { +#include "playlist.h" +#include "player_control.h" +#include "text_file.h" +#include "conf.h" +} + +#include +#include + +#define PLAYLIST_STATE_FILE_STATE "state: " +#define PLAYLIST_STATE_FILE_RANDOM "random: " +#define PLAYLIST_STATE_FILE_REPEAT "repeat: " +#define PLAYLIST_STATE_FILE_SINGLE "single: " +#define PLAYLIST_STATE_FILE_CONSUME "consume: " +#define PLAYLIST_STATE_FILE_CURRENT "current: " +#define PLAYLIST_STATE_FILE_TIME "time: " +#define PLAYLIST_STATE_FILE_CROSSFADE "crossfade: " +#define PLAYLIST_STATE_FILE_MIXRAMPDB "mixrampdb: " +#define PLAYLIST_STATE_FILE_MIXRAMPDELAY "mixrampdelay: " +#define PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "playlist_begin" +#define PLAYLIST_STATE_FILE_PLAYLIST_END "playlist_end" + +#define PLAYLIST_STATE_FILE_STATE_PLAY "play" +#define PLAYLIST_STATE_FILE_STATE_PAUSE "pause" +#define PLAYLIST_STATE_FILE_STATE_STOP "stop" + +#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX + +void +playlist_state_save(FILE *fp, const struct playlist *playlist, + struct player_control *pc) +{ + struct player_status player_status; + + pc_get_status(pc, &player_status); + + fputs(PLAYLIST_STATE_FILE_STATE, fp); + + if (playlist->playing) { + switch (player_status.state) { + case PLAYER_STATE_PAUSE: + fputs(PLAYLIST_STATE_FILE_STATE_PAUSE "\n", fp); + break; + default: + fputs(PLAYLIST_STATE_FILE_STATE_PLAY "\n", fp); + } + fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", + queue_order_to_position(&playlist->queue, + playlist->current)); + fprintf(fp, PLAYLIST_STATE_FILE_TIME "%i\n", + (int)player_status.elapsed_time); + } else { + fputs(PLAYLIST_STATE_FILE_STATE_STOP "\n", fp); + + if (playlist->current >= 0) + fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", + queue_order_to_position(&playlist->queue, + playlist->current)); + } + + fprintf(fp, PLAYLIST_STATE_FILE_RANDOM "%i\n", playlist->queue.random); + fprintf(fp, PLAYLIST_STATE_FILE_REPEAT "%i\n", playlist->queue.repeat); + fprintf(fp, PLAYLIST_STATE_FILE_SINGLE "%i\n", playlist->queue.single); + fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n", + playlist->queue.consume); + fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n", + (int)(pc_get_cross_fade(pc))); + fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", + pc_get_mixramp_db(pc)); + fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n", + pc_get_mixramp_delay(pc)); + fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp); + queue_save(fp, &playlist->queue); + fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp); +} + +static void +playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist) +{ + const char *line = read_text_line(fp, buffer); + if (line == NULL) { + g_warning("No playlist in state file"); + return; + } + + while (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_PLAYLIST_END)) { + queue_load_song(fp, buffer, line, &playlist->queue); + + line = read_text_line(fp, buffer); + if (line == NULL) { + g_warning("'" PLAYLIST_STATE_FILE_PLAYLIST_END + "' not found in state file"); + break; + } + } + + queue_increment_version(&playlist->queue); +} + +bool +playlist_state_restore(const char *line, FILE *fp, GString *buffer, + struct playlist *playlist, struct player_control *pc) +{ + int current = -1; + int seek_time = 0; + enum player_state state = PLAYER_STATE_STOP; + bool random_mode = false; + + if (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_STATE)) + return false; + + line += sizeof(PLAYLIST_STATE_FILE_STATE) - 1; + + if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PLAY) == 0) + state = PLAYER_STATE_PLAY; + else if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PAUSE) == 0) + state = PLAYER_STATE_PAUSE; + + while ((line = read_text_line(fp, buffer)) != NULL) { + if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_TIME)) { + seek_time = + atoi(&(line[strlen(PLAYLIST_STATE_FILE_TIME)])); + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_REPEAT)) { + if (strcmp + (&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]), + "1") == 0) { + playlist_set_repeat(playlist, pc, true); + } else + playlist_set_repeat(playlist, pc, false); + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) { + if (strcmp + (&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]), + "1") == 0) { + playlist_set_single(playlist, pc, true); + } else + playlist_set_single(playlist, pc, false); + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) { + if (strcmp + (&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]), + "1") == 0) { + playlist_set_consume(playlist, true); + } else + playlist_set_consume(playlist, false); + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) { + pc_set_cross_fade(pc, + atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE))); + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) { + pc_set_mixramp_db(pc, + atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB))); + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) { + pc_set_mixramp_delay(pc, + atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY))); + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) { + random_mode = + strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM), + "1") == 0; + } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CURRENT)) { + current = atoi(&(line + [strlen + (PLAYLIST_STATE_FILE_CURRENT)])); + } else if (g_str_has_prefix(line, + PLAYLIST_STATE_FILE_PLAYLIST_BEGIN)) { + playlist_state_load(fp, buffer, playlist); + } + } + + playlist_set_random(playlist, pc, random_mode); + + if (!queue_is_empty(&playlist->queue)) { + if (!queue_valid_position(&playlist->queue, current)) + current = 0; + + if (state == PLAYER_STATE_PLAY && + config_get_bool("restore_paused", false)) + /* the user doesn't want MPD to auto-start + playback after startup; fall back to + "pause" */ + state = PLAYER_STATE_PAUSE; + + /* enable all devices for the first time; this must be + called here, after the audio output states were + restored, before playback begins */ + if (state != PLAYER_STATE_STOP) + pc_update_audio(pc); + + if (state == PLAYER_STATE_STOP /* && config_option */) + playlist->current = current; + else if (seek_time == 0) + playlist_play(playlist, pc, current); + else + playlist_seek_song(playlist, pc, current, seek_time); + + if (state == PLAYER_STATE_PAUSE) + pc_pause(pc); + } + + return true; +} + +unsigned +playlist_state_get_hash(const struct playlist *playlist, + struct player_control *pc) +{ + struct player_status player_status; + + pc_get_status(pc, &player_status); + + return playlist->queue.version ^ + (player_status.state != PLAYER_STATE_STOP + ? ((int)player_status.elapsed_time << 8) + : 0) ^ + (playlist->current >= 0 + ? (queue_order_to_position(&playlist->queue, + playlist->current) << 16) + : 0) ^ + ((int)pc_get_cross_fade(pc) << 20) ^ + (player_status.state << 24) ^ + (playlist->queue.random << 27) ^ + (playlist->queue.repeat << 28) ^ + (playlist->queue.single << 29) ^ + (playlist->queue.consume << 30) ^ + (playlist->queue.random << 31); +} diff --git a/src/PlaylistState.hxx b/src/PlaylistState.hxx new file mode 100644 index 000000000..d38fe9d12 --- /dev/null +++ b/src/PlaylistState.hxx @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003-2013 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. + */ + +/* + * Saving and loading the playlist to/from the state file. + * + */ + +#ifndef MPD_PLAYLIST_STATE_HXX +#define MPD_PLAYLIST_STATE_HXX + +#include +#include + +struct playlist; +struct player_control; + +void +playlist_state_save(FILE *fp, const struct playlist *playlist, + struct player_control *pc); + +bool +playlist_state_restore(const char *line, FILE *fp, GString *buffer, + struct playlist *playlist, struct player_control *pc); + +/** + * Generates a hash number for the current state of the playlist and + * the playback options. This is used by timer_save_state_file() to + * determine whether the state has changed and the state file should + * be saved. + */ +unsigned +playlist_state_get_hash(const struct playlist *playlist, + struct player_control *pc); + +#endif diff --git a/src/QueueSave.cxx b/src/QueueSave.cxx new file mode 100644 index 000000000..96713c700 --- /dev/null +++ b/src/QueueSave.cxx @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2003-2013 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 "QueueSave.hxx" +#include "song.h" +#include "SongSave.hxx" + +extern "C" { +#include "queue.h" +#include "uri.h" +#include "database.h" +#include "text_file.h" +} + +#include + +#define PRIO_LABEL "Prio: " + +static void +queue_save_database_song(FILE *fp, int idx, const struct song *song) +{ + char *uri = song_get_uri(song); + + fprintf(fp, "%i:%s\n", idx, uri); + g_free(uri); +} + +static void +queue_save_full_song(FILE *fp, const struct song *song) +{ + song_save(fp, song); +} + +static void +queue_save_song(FILE *fp, int idx, const struct song *song) +{ + if (song_in_database(song)) + queue_save_database_song(fp, idx, song); + else + queue_save_full_song(fp, song); +} + +void +queue_save(FILE *fp, const struct queue *queue) +{ + for (unsigned i = 0; i < queue_length(queue); i++) { + uint8_t prio = queue_get_priority_at_position(queue, i); + if (prio != 0) + fprintf(fp, PRIO_LABEL "%u\n", prio); + + queue_save_song(fp, i, queue_get(queue, i)); + } +} + +static struct song * +get_song(const char *uri) +{ + return uri_has_scheme(uri) + ? song_remote_new(uri) + : db_get_song(uri); +} + +void +queue_load_song(FILE *fp, GString *buffer, const char *line, + struct queue *queue) +{ + struct song *song; + + if (queue_is_full(queue)) + return; + + uint8_t priority = 0; + if (g_str_has_prefix(line, PRIO_LABEL)) { + priority = strtoul(line + sizeof(PRIO_LABEL) - 1, NULL, 10); + + line = read_text_line(fp, buffer); + if (line == NULL) + return; + } + + if (g_str_has_prefix(line, SONG_BEGIN)) { + const char *uri = line + sizeof(SONG_BEGIN) - 1; + if (!uri_has_scheme(uri) && !g_path_is_absolute(uri)) + return; + + GError *error = NULL; + song = song_load(fp, NULL, uri, buffer, &error); + if (song == NULL) { + g_warning("%s", error->message); + g_error_free(error); + return; + } + } else { + char *endptr; + long ret = strtol(line, &endptr, 10); + if (ret < 0 || *endptr != ':' || endptr[1] == 0) { + g_warning("Malformed playlist line in state file"); + return; + } + + line = endptr + 1; + + song = get_song(line); + if (song == NULL) + return; + } + + queue_append(queue, song, priority); + + if (song_in_database(song)) + db_return_song(song); +} diff --git a/src/QueueSave.hxx b/src/QueueSave.hxx new file mode 100644 index 000000000..d6b09329b --- /dev/null +++ b/src/QueueSave.hxx @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2003-2013 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. + */ + +/* + * This library saves the queue into the state file, and also loads it + * back into memory. + */ + +#ifndef MPD_QUEUE_SAVE_HXX +#define MPD_QUEUE_SAVE_HXX + +#include +#include + +struct queue; + +void +queue_save(FILE *fp, const struct queue *queue); + +/** + * Loads one song from the state file and appends it to the queue. + */ +void +queue_load_song(FILE *fp, GString *buffer, const char *line, + struct queue *queue); + +#endif diff --git a/src/SongSave.cxx b/src/SongSave.cxx new file mode 100644 index 000000000..21d073b86 --- /dev/null +++ b/src/SongSave.cxx @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2003-2013 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 "SongSave.hxx" +#include "song.h" +#include "TagSave.hxx" +#include "directory.h" + +extern "C" { +#include "tag.h" +#include "text_file.h" +#include "string_util.h" +} + +#include + +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "song" + +#define SONG_MTIME "mtime" +#define SONG_END "song_end" + +static GQuark +song_save_quark(void) +{ + return g_quark_from_static_string("song_save"); +} + +void +song_save(FILE *fp, const struct song *song) +{ + fprintf(fp, SONG_BEGIN "%s\n", song->uri); + + if (song->end_ms > 0) + fprintf(fp, "Range: %u-%u\n", song->start_ms, song->end_ms); + else if (song->start_ms > 0) + fprintf(fp, "Range: %u-\n", song->start_ms); + + if (song->tag != NULL) + tag_save(fp, song->tag); + + fprintf(fp, SONG_MTIME ": %li\n", (long)song->mtime); + fprintf(fp, SONG_END "\n"); +} + +struct song * +song_load(FILE *fp, struct directory *parent, const char *uri, + GString *buffer, GError **error_r) +{ + struct song *song = parent != NULL + ? song_file_new(uri, parent) + : song_remote_new(uri); + char *line, *colon; + enum tag_type type; + const char *value; + + while ((line = read_text_line(fp, buffer)) != NULL && + strcmp(line, SONG_END) != 0) { + colon = strchr(line, ':'); + if (colon == NULL || colon == line) { + if (song->tag != NULL) + tag_end_add(song->tag); + song_free(song); + + g_set_error(error_r, song_save_quark(), 0, + "unknown line in db: %s", line); + return NULL; + } + + *colon++ = 0; + value = strchug_fast_c(colon); + + if ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) { + if (!song->tag) { + song->tag = tag_new(); + tag_begin_add(song->tag); + } + + tag_add_item(song->tag, type, value); + } else if (strcmp(line, "Time") == 0) { + if (!song->tag) { + song->tag = tag_new(); + tag_begin_add(song->tag); + } + + song->tag->time = atoi(value); + } else if (strcmp(line, "Playlist") == 0) { + if (!song->tag) { + song->tag = tag_new(); + tag_begin_add(song->tag); + } + + song->tag->has_playlist = strcmp(value, "yes") == 0; + } else if (strcmp(line, SONG_MTIME) == 0) { + song->mtime = atoi(value); + } else if (strcmp(line, "Range") == 0) { + char *endptr; + + song->start_ms = strtoul(value, &endptr, 10); + if (*endptr == '-') + song->end_ms = strtoul(endptr + 1, NULL, 10); + } else { + if (song->tag != NULL) + tag_end_add(song->tag); + song_free(song); + + g_set_error(error_r, song_save_quark(), 0, + "unknown line in db: %s", line); + return NULL; + } + } + + if (song->tag != NULL) + tag_end_add(song->tag); + + return song; +} diff --git a/src/SongSave.hxx b/src/SongSave.hxx new file mode 100644 index 000000000..d8805acd7 --- /dev/null +++ b/src/SongSave.hxx @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2003-2013 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_SONG_SAVE_HXX +#define MPD_SONG_SAVE_HXX + +#include + +#include + +#define SONG_BEGIN "song_begin: " + +struct song; +struct directory; + +void +song_save(FILE *fp, const struct song *song); + +/** + * Loads a song from the input file. Reading stops after the + * "song_end" line. + * + * @param error_r location to store the error occurring, or NULL to + * ignore errors + * @return true on success, false on error + */ +struct song * +song_load(FILE *fp, struct directory *parent, const char *uri, + GString *buffer, GError **error_r); + +#endif diff --git a/src/StateFile.cxx b/src/StateFile.cxx new file mode 100644 index 000000000..6635d9f9d --- /dev/null +++ b/src/StateFile.cxx @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2003-2013 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 "StateFile.hxx" +#include "OutputState.hxx" +#include "playlist.h" +#include "PlaylistState.hxx" + +extern "C" { +#include "volume.h" +#include "text_file.h" +} + +#include +#include +#include +#include + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "state_file" + +static char *state_file_path; + +/** the GLib source id for the save timer */ +static guint save_state_source_id; + +/** + * These version numbers determine whether we need to save the state + * file. If nothing has changed, we won't let the hard drive spin up. + */ +static unsigned prev_volume_version, prev_output_version, + prev_playlist_version; + +static void +state_file_write(struct player_control *pc) +{ + FILE *fp; + + assert(state_file_path != NULL); + + g_debug("Saving state file %s", state_file_path); + + fp = fopen(state_file_path, "w"); + if (G_UNLIKELY(!fp)) { + g_warning("failed to create %s: %s", + state_file_path, g_strerror(errno)); + return; + } + + save_sw_volume_state(fp); + audio_output_state_save(fp); + playlist_state_save(fp, &g_playlist, pc); + + fclose(fp); + + prev_volume_version = sw_volume_state_get_hash(); + prev_output_version = audio_output_state_get_version(); + prev_playlist_version = playlist_state_get_hash(&g_playlist, pc); +} + +static void +state_file_read(struct player_control *pc) +{ + FILE *fp; + bool success; + + assert(state_file_path != NULL); + + g_debug("Loading state file %s", state_file_path); + + fp = fopen(state_file_path, "r"); + if (G_UNLIKELY(!fp)) { + g_warning("failed to open %s: %s", + state_file_path, g_strerror(errno)); + return; + } + + GString *buffer = g_string_sized_new(1024); + const char *line; + while ((line = read_text_line(fp, buffer)) != NULL) { + success = read_sw_volume_state(line) || + audio_output_state_read(line) || + playlist_state_restore(line, fp, buffer, + &g_playlist, pc); + if (!success) + g_warning("Unrecognized line in state file: %s", line); + } + + fclose(fp); + + prev_volume_version = sw_volume_state_get_hash(); + prev_output_version = audio_output_state_get_version(); + prev_playlist_version = playlist_state_get_hash(&g_playlist, pc); + + + g_string_free(buffer, true); +} + +/** + * This function is called every 5 minutes by the GLib main loop, and + * saves the state file. + */ +static gboolean +timer_save_state_file(gpointer data) +{ + struct player_control *pc = (struct player_control *)data; + + if (prev_volume_version == sw_volume_state_get_hash() && + prev_output_version == audio_output_state_get_version() && + prev_playlist_version == playlist_state_get_hash(&g_playlist, pc)) + /* nothing has changed - don't save the state file, + don't spin up the hard disk */ + return true; + + state_file_write(pc); + return true; +} + +void +state_file_init(const char *path, struct player_control *pc) +{ + assert(state_file_path == NULL); + + if (path == NULL) + return; + + state_file_path = g_strdup(path); + state_file_read(pc); + + save_state_source_id = g_timeout_add_seconds(5 * 60, + timer_save_state_file, + pc); +} + +void +state_file_finish(struct player_control *pc) +{ + if (state_file_path == NULL) + /* no state file configured, no cleanup required */ + return; + + if (save_state_source_id != 0) + g_source_remove(save_state_source_id); + + state_file_write(pc); + + g_free(state_file_path); +} diff --git a/src/StateFile.hxx b/src/StateFile.hxx new file mode 100644 index 000000000..77629aba9 --- /dev/null +++ b/src/StateFile.hxx @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2003-2013 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_STATE_FILE_HXX +#define MPD_STATE_FILE_HXX + +struct player_control; + +void +state_file_init(const char *path, struct player_control *pc); + +void +state_file_finish(struct player_control *pc); + +void write_state_file(void); + +#endif /* STATE_FILE_H */ diff --git a/src/TagSave.cxx b/src/TagSave.cxx new file mode 100644 index 000000000..639dc2d97 --- /dev/null +++ b/src/TagSave.cxx @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2003-2013 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 "TagSave.hxx" +#include "tag.h" +#include "tag_internal.h" +#include "song.h" + +void tag_save(FILE *file, const struct tag *tag) +{ + if (tag->time >= 0) + fprintf(file, SONG_TIME "%i\n", tag->time); + + if (tag->has_playlist) + fprintf(file, "Playlist: yes\n"); + + for (unsigned i = 0; i < tag->num_items; i++) + fprintf(file, "%s: %s\n", + tag_item_names[tag->items[i]->type], + tag->items[i]->value); +} diff --git a/src/TagSave.hxx b/src/TagSave.hxx new file mode 100644 index 000000000..a7ccfa613 --- /dev/null +++ b/src/TagSave.hxx @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2003-2013 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_TAG_SAVE_HXX +#define MPD_TAG_SAVE_HXX + +#include + +struct tag; + +void tag_save(FILE *file, const struct tag *tag); + +#endif diff --git a/src/db/SimpleDatabasePlugin.cxx b/src/db/SimpleDatabasePlugin.cxx index d83c1ca73..4b92da6cf 100644 --- a/src/db/SimpleDatabasePlugin.cxx +++ b/src/db/SimpleDatabasePlugin.cxx @@ -22,10 +22,10 @@ #include "DatabaseSelection.hxx" #include "DatabaseHelpers.hxx" #include "SongFilter.hxx" +#include "DatabaseSave.hxx" extern "C" { #include "db_error.h" -#include "db_save.h" #include "db_lock.h" #include "conf.h" } diff --git a/src/db_save.c b/src/db_save.c deleted file mode 100644 index 4af9d58b8..000000000 --- a/src/db_save.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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 "db_save.h" -#include "db_lock.h" -#include "directory.h" -#include "directory_save.h" -#include "song.h" -#include "path.h" -#include "text_file.h" -#include "tag.h" -#include "tag_internal.h" - -#include - -#include -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "database" - -#define DIRECTORY_INFO_BEGIN "info_begin" -#define DIRECTORY_INFO_END "info_end" -#define DB_FORMAT_PREFIX "format: " -#define DIRECTORY_MPD_VERSION "mpd_version: " -#define DIRECTORY_FS_CHARSET "fs_charset: " -#define DB_TAG_PREFIX "tag: " - -enum { - DB_FORMAT = 1, -}; - -G_GNUC_CONST -static GQuark -db_quark(void) -{ - return g_quark_from_static_string("database"); -} - -void -db_save_internal(FILE *fp, const struct directory *music_root) -{ - assert(music_root != NULL); - - fprintf(fp, "%s\n", DIRECTORY_INFO_BEGIN); - fprintf(fp, DB_FORMAT_PREFIX "%u\n", DB_FORMAT); - fprintf(fp, "%s%s\n", DIRECTORY_MPD_VERSION, VERSION); - fprintf(fp, "%s%s\n", DIRECTORY_FS_CHARSET, path_get_fs_charset()); - - for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) - if (!ignore_tag_items[i]) - fprintf(fp, DB_TAG_PREFIX "%s\n", tag_item_names[i]); - - fprintf(fp, "%s\n", DIRECTORY_INFO_END); - - directory_save(fp, music_root); -} - -bool -db_load_internal(FILE *fp, struct directory *music_root, GError **error) -{ - GString *buffer = g_string_sized_new(1024); - char *line; - int format = 0; - bool found_charset = false, found_version = false; - bool success; - bool tags[TAG_NUM_OF_ITEM_TYPES]; - - assert(music_root != NULL); - - /* get initial info */ - line = read_text_line(fp, buffer); - if (line == NULL || strcmp(DIRECTORY_INFO_BEGIN, line) != 0) { - g_set_error(error, db_quark(), 0, "Database corrupted"); - g_string_free(buffer, true); - return false; - } - - memset(tags, false, sizeof(tags)); - - while ((line = read_text_line(fp, buffer)) != NULL && - strcmp(line, DIRECTORY_INFO_END) != 0) { - if (g_str_has_prefix(line, DB_FORMAT_PREFIX)) { - format = atoi(line + sizeof(DB_FORMAT_PREFIX) - 1); - } else if (g_str_has_prefix(line, DIRECTORY_MPD_VERSION)) { - if (found_version) { - g_set_error(error, db_quark(), 0, - "Duplicate version line"); - g_string_free(buffer, true); - return false; - } - - found_version = true; - } else if (g_str_has_prefix(line, DIRECTORY_FS_CHARSET)) { - const char *new_charset, *old_charset; - - if (found_charset) { - g_set_error(error, db_quark(), 0, - "Duplicate charset line"); - g_string_free(buffer, true); - return false; - } - - found_charset = true; - - new_charset = line + sizeof(DIRECTORY_FS_CHARSET) - 1; - old_charset = path_get_fs_charset(); - if (old_charset != NULL - && strcmp(new_charset, old_charset)) { - g_set_error(error, db_quark(), 0, - "Existing database has charset " - "\"%s\" instead of \"%s\"; " - "discarding database file", - new_charset, old_charset); - g_string_free(buffer, true); - return false; - } - } else if (g_str_has_prefix(line, DB_TAG_PREFIX)) { - const char *name = line + sizeof(DB_TAG_PREFIX) - 1; - enum tag_type tag = tag_name_parse(name); - if (tag == TAG_NUM_OF_ITEM_TYPES) { - g_set_error(error, db_quark(), 0, - "Unrecognized tag '%s', " - "discarding database file", - name); - return false; - } - - tags[tag] = true; - } else { - g_set_error(error, db_quark(), 0, - "Malformed line: %s", line); - g_string_free(buffer, true); - return false; - } - } - - if (format != DB_FORMAT) { - g_set_error(error, db_quark(), 0, - "Database format mismatch, " - "discarding database file"); - return false; - } - - for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) { - if (!ignore_tag_items[i] && !tags[i]) { - g_set_error(error, db_quark(), 0, - "Tag list mismatch, " - "discarding database file"); - return false; - } - } - - g_debug("reading DB"); - - db_lock(); - success = directory_load(fp, music_root, buffer, error); - db_unlock(); - g_string_free(buffer, true); - - return success; -} diff --git a/src/db_save.h b/src/db_save.h deleted file mode 100644 index d232d7331..000000000 --- a/src/db_save.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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_DB_SAVE_H -#define MPD_DB_SAVE_H - -#include "gerror.h" - -#include -#include - -struct directory; - -void -db_save_internal(FILE *file, const struct directory *root); - -bool -db_load_internal(FILE *file, struct directory *root, GError **error); - -#endif diff --git a/src/directory_save.c b/src/directory_save.c deleted file mode 100644 index de1df050a..000000000 --- a/src/directory_save.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 "directory_save.h" -#include "directory.h" -#include "song.h" -#include "text_file.h" -#include "song_save.h" -#include "playlist_database.h" - -#include -#include - -#define DIRECTORY_DIR "directory: " -#define DIRECTORY_MTIME "mtime: " -#define DIRECTORY_BEGIN "begin: " -#define DIRECTORY_END "end: " - -/** - * The quark used for GError.domain. - */ -static inline GQuark -directory_quark(void) -{ - return g_quark_from_static_string("directory"); -} - -void -directory_save(FILE *fp, const struct directory *directory) -{ - if (!directory_is_root(directory)) { - fprintf(fp, DIRECTORY_MTIME "%lu\n", - (unsigned long)directory->mtime); - - fprintf(fp, "%s%s\n", DIRECTORY_BEGIN, - directory_get_path(directory)); - } - - struct directory *cur; - directory_for_each_child(cur, directory) { - char *base = g_path_get_basename(cur->path); - - fprintf(fp, DIRECTORY_DIR "%s\n", base); - g_free(base); - - directory_save(fp, cur); - - if (ferror(fp)) - return; - } - - struct song *song; - directory_for_each_song(song, directory) - song_save(fp, song); - - playlist_vector_save(fp, &directory->playlists); - - if (!directory_is_root(directory)) - fprintf(fp, DIRECTORY_END "%s\n", - directory_get_path(directory)); -} - -static struct directory * -directory_load_subdir(FILE *fp, struct directory *parent, const char *name, - GString *buffer, GError **error_r) -{ - const char *line; - bool success; - - if (directory_get_child(parent, name) != NULL) { - g_set_error(error_r, directory_quark(), 0, - "Duplicate subdirectory '%s'", name); - return NULL; - } - - struct directory *directory = directory_new_child(parent, name); - - line = read_text_line(fp, buffer); - if (line == NULL) { - g_set_error(error_r, directory_quark(), 0, - "Unexpected end of file"); - directory_delete(directory); - return NULL; - } - - if (g_str_has_prefix(line, DIRECTORY_MTIME)) { - directory->mtime = - g_ascii_strtoull(line + sizeof(DIRECTORY_MTIME) - 1, - NULL, 10); - - line = read_text_line(fp, buffer); - if (line == NULL) { - g_set_error(error_r, directory_quark(), 0, - "Unexpected end of file"); - directory_delete(directory); - return NULL; - } - } - - if (!g_str_has_prefix(line, DIRECTORY_BEGIN)) { - g_set_error(error_r, directory_quark(), 0, - "Malformed line: %s", line); - directory_delete(directory); - return NULL; - } - - success = directory_load(fp, directory, buffer, error_r); - if (!success) { - directory_delete(directory); - return NULL; - } - - return directory; -} - -bool -directory_load(FILE *fp, struct directory *directory, - GString *buffer, GError **error) -{ - const char *line; - - while ((line = read_text_line(fp, buffer)) != NULL && - !g_str_has_prefix(line, DIRECTORY_END)) { - if (g_str_has_prefix(line, DIRECTORY_DIR)) { - struct directory *subdir = - directory_load_subdir(fp, directory, - line + sizeof(DIRECTORY_DIR) - 1, - buffer, error); - if (subdir == NULL) - return false; - } else if (g_str_has_prefix(line, SONG_BEGIN)) { - const char *name = line + sizeof(SONG_BEGIN) - 1; - struct song *song; - - if (directory_get_song(directory, name) != NULL) { - g_set_error(error, directory_quark(), 0, - "Duplicate song '%s'", name); - return NULL; - } - - song = song_load(fp, directory, name, - buffer, error); - if (song == NULL) - return false; - - directory_add_song(directory, song); - } else if (g_str_has_prefix(line, PLAYLIST_META_BEGIN)) { - /* duplicate the name, because - playlist_metadata_load() will overwrite the - buffer */ - char *name = g_strdup(line + sizeof(PLAYLIST_META_BEGIN) - 1); - - if (!playlist_metadata_load(fp, &directory->playlists, - name, buffer, error)) { - g_free(name); - return false; - } - - g_free(name); - } else { - g_set_error(error, directory_quark(), 0, - "Malformed line: %s", line); - return false; - } - } - - return true; -} diff --git a/src/directory_save.h b/src/directory_save.h deleted file mode 100644 index 2d0056830..000000000 --- a/src/directory_save.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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_DIRECTORY_SAVE_H -#define MPD_DIRECTORY_SAVE_H - -#include - -#include -#include - -struct directory; - -void -directory_save(FILE *fp, const struct directory *directory); - -bool -directory_load(FILE *fp, struct directory *directory, - GString *buffer, GError **error); - -#endif diff --git a/src/output_state.c b/src/output_state.c deleted file mode 100644 index 7bcafb36b..000000000 --- a/src/output_state.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. - */ - -/* - * Saving and loading the audio output states to/from the state file. - * - */ - -#include "config.h" -#include "output_state.h" -#include "output_internal.h" -#include "output_all.h" - -#include - -#include -#include -#include - -#define AUDIO_DEVICE_STATE "audio_device_state:" - -unsigned audio_output_state_version; - -void -audio_output_state_save(FILE *fp) -{ - unsigned n = audio_output_count(); - - assert(n > 0); - - for (unsigned i = 0; i < n; ++i) { - const struct audio_output *ao = audio_output_get(i); - - fprintf(fp, AUDIO_DEVICE_STATE "%d:%s\n", - ao->enabled, ao->name); - } -} - -bool -audio_output_state_read(const char *line) -{ - long value; - char *endptr; - const char *name; - struct audio_output *ao; - - if (!g_str_has_prefix(line, AUDIO_DEVICE_STATE)) - return false; - - line += sizeof(AUDIO_DEVICE_STATE) - 1; - - value = strtol(line, &endptr, 10); - if (*endptr != ':' || (value != 0 && value != 1)) - return false; - - if (value != 0) - /* state is "enabled": no-op */ - return true; - - name = endptr + 1; - ao = audio_output_find(name); - if (ao == NULL) { - g_debug("Ignoring device state for '%s'", name); - return true; - } - - ao->enabled = false; - return true; -} - -unsigned -audio_output_state_get_version(void) -{ - return audio_output_state_version; -} diff --git a/src/output_state.h b/src/output_state.h deleted file mode 100644 index 320a3520a..000000000 --- a/src/output_state.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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. - */ - -/* - * Saving and loading the audio output states to/from the state file. - * - */ - -#ifndef OUTPUT_STATE_H -#define OUTPUT_STATE_H - -#include -#include - -bool -audio_output_state_read(const char *line); - -void -audio_output_state_save(FILE *fp); - -/** - * Generates a version number for the current state of the audio - * outputs. This is used by timer_save_state_file() to determine - * whether the state has changed and the state file should be saved. - */ -unsigned -audio_output_state_get_version(void); - -#endif diff --git a/src/playlist_database.c b/src/playlist_database.c deleted file mode 100644 index 6b9d87155..000000000 --- a/src/playlist_database.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 "playlist_database.h" -#include "playlist_vector.h" -#include "text_file.h" -#include "string_util.h" - -#include -#include - -static GQuark -playlist_database_quark(void) -{ - return g_quark_from_static_string("playlist_database"); -} - -void -playlist_vector_save(FILE *fp, const struct list_head *pv) -{ - struct playlist_metadata *pm; - playlist_vector_for_each(pm, pv) - fprintf(fp, PLAYLIST_META_BEGIN "%s\n" - "mtime: %li\n" - "playlist_end\n", - pm->name, (long)pm->mtime); -} - -bool -playlist_metadata_load(FILE *fp, struct list_head *pv, const char *name, - GString *buffer, GError **error_r) -{ - struct playlist_metadata pm = { - .mtime = 0, - }; - char *line, *colon; - const char *value; - - while ((line = read_text_line(fp, buffer)) != NULL && - strcmp(line, "playlist_end") != 0) { - colon = strchr(line, ':'); - if (colon == NULL || colon == line) { - g_set_error(error_r, playlist_database_quark(), 0, - "unknown line in db: %s", line); - return false; - } - - *colon++ = 0; - value = strchug_fast_c(colon); - - if (strcmp(line, "mtime") == 0) - pm.mtime = strtol(value, NULL, 10); - else { - g_set_error(error_r, playlist_database_quark(), 0, - "unknown line in db: %s", line); - return false; - } - } - - playlist_vector_update_or_add(pv, name, pm.mtime); - return true; -} diff --git a/src/playlist_database.h b/src/playlist_database.h deleted file mode 100644 index 3238fa06b..000000000 --- a/src/playlist_database.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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_PLAYLIST_DATABASE_H -#define MPD_PLAYLIST_DATABASE_H - -#include "check.h" - -#include -#include -#include - -#define PLAYLIST_META_BEGIN "playlist_begin: " - -struct list_head; - -void -playlist_vector_save(FILE *fp, const struct list_head *pv); - -bool -playlist_metadata_load(FILE *fp, struct list_head *pv, const char *name, - GString *buffer, GError **error_r); - -#endif diff --git a/src/playlist_global.c b/src/playlist_global.c index 43bf26755..e66febce0 100644 --- a/src/playlist_global.c +++ b/src/playlist_global.c @@ -24,7 +24,6 @@ #include "config.h" #include "playlist.h" -#include "playlist_state.h" #include "event_pipe.h" #include "Main.hxx" diff --git a/src/playlist_state.c b/src/playlist_state.c deleted file mode 100644 index 4aa2c2c92..000000000 --- a/src/playlist_state.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * 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. - */ - -/* - * Saving and loading the playlist to/from the state file. - * - */ - -#include "config.h" -#include "playlist_state.h" -#include "playlist.h" -#include "player_control.h" -#include "queue_save.h" -#include "path.h" -#include "text_file.h" -#include "conf.h" - -#include -#include - -#define PLAYLIST_STATE_FILE_STATE "state: " -#define PLAYLIST_STATE_FILE_RANDOM "random: " -#define PLAYLIST_STATE_FILE_REPEAT "repeat: " -#define PLAYLIST_STATE_FILE_SINGLE "single: " -#define PLAYLIST_STATE_FILE_CONSUME "consume: " -#define PLAYLIST_STATE_FILE_CURRENT "current: " -#define PLAYLIST_STATE_FILE_TIME "time: " -#define PLAYLIST_STATE_FILE_CROSSFADE "crossfade: " -#define PLAYLIST_STATE_FILE_MIXRAMPDB "mixrampdb: " -#define PLAYLIST_STATE_FILE_MIXRAMPDELAY "mixrampdelay: " -#define PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "playlist_begin" -#define PLAYLIST_STATE_FILE_PLAYLIST_END "playlist_end" - -#define PLAYLIST_STATE_FILE_STATE_PLAY "play" -#define PLAYLIST_STATE_FILE_STATE_PAUSE "pause" -#define PLAYLIST_STATE_FILE_STATE_STOP "stop" - -#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX - -void -playlist_state_save(FILE *fp, const struct playlist *playlist, - struct player_control *pc) -{ - struct player_status player_status; - - pc_get_status(pc, &player_status); - - fputs(PLAYLIST_STATE_FILE_STATE, fp); - - if (playlist->playing) { - switch (player_status.state) { - case PLAYER_STATE_PAUSE: - fputs(PLAYLIST_STATE_FILE_STATE_PAUSE "\n", fp); - break; - default: - fputs(PLAYLIST_STATE_FILE_STATE_PLAY "\n", fp); - } - fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", - queue_order_to_position(&playlist->queue, - playlist->current)); - fprintf(fp, PLAYLIST_STATE_FILE_TIME "%i\n", - (int)player_status.elapsed_time); - } else { - fputs(PLAYLIST_STATE_FILE_STATE_STOP "\n", fp); - - if (playlist->current >= 0) - fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", - queue_order_to_position(&playlist->queue, - playlist->current)); - } - - fprintf(fp, PLAYLIST_STATE_FILE_RANDOM "%i\n", playlist->queue.random); - fprintf(fp, PLAYLIST_STATE_FILE_REPEAT "%i\n", playlist->queue.repeat); - fprintf(fp, PLAYLIST_STATE_FILE_SINGLE "%i\n", playlist->queue.single); - fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n", - playlist->queue.consume); - fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n", - (int)(pc_get_cross_fade(pc))); - fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", - pc_get_mixramp_db(pc)); - fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n", - pc_get_mixramp_delay(pc)); - fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp); - queue_save(fp, &playlist->queue); - fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp); -} - -static void -playlist_state_load(FILE *fp, GString *buffer, struct playlist *playlist) -{ - const char *line = read_text_line(fp, buffer); - if (line == NULL) { - g_warning("No playlist in state file"); - return; - } - - while (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_PLAYLIST_END)) { - queue_load_song(fp, buffer, line, &playlist->queue); - - line = read_text_line(fp, buffer); - if (line == NULL) { - g_warning("'" PLAYLIST_STATE_FILE_PLAYLIST_END - "' not found in state file"); - break; - } - } - - queue_increment_version(&playlist->queue); -} - -bool -playlist_state_restore(const char *line, FILE *fp, GString *buffer, - struct playlist *playlist, struct player_control *pc) -{ - int current = -1; - int seek_time = 0; - enum player_state state = PLAYER_STATE_STOP; - bool random_mode = false; - - if (!g_str_has_prefix(line, PLAYLIST_STATE_FILE_STATE)) - return false; - - line += sizeof(PLAYLIST_STATE_FILE_STATE) - 1; - - if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PLAY) == 0) - state = PLAYER_STATE_PLAY; - else if (strcmp(line, PLAYLIST_STATE_FILE_STATE_PAUSE) == 0) - state = PLAYER_STATE_PAUSE; - - while ((line = read_text_line(fp, buffer)) != NULL) { - if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_TIME)) { - seek_time = - atoi(&(line[strlen(PLAYLIST_STATE_FILE_TIME)])); - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_REPEAT)) { - if (strcmp - (&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]), - "1") == 0) { - playlist_set_repeat(playlist, pc, true); - } else - playlist_set_repeat(playlist, pc, false); - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) { - if (strcmp - (&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]), - "1") == 0) { - playlist_set_single(playlist, pc, true); - } else - playlist_set_single(playlist, pc, false); - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) { - if (strcmp - (&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]), - "1") == 0) { - playlist_set_consume(playlist, true); - } else - playlist_set_consume(playlist, false); - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) { - pc_set_cross_fade(pc, - atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE))); - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB)) { - pc_set_mixramp_db(pc, - atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDB))); - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY)) { - pc_set_mixramp_delay(pc, - atof(line + strlen(PLAYLIST_STATE_FILE_MIXRAMPDELAY))); - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_RANDOM)) { - random_mode = - strcmp(line + strlen(PLAYLIST_STATE_FILE_RANDOM), - "1") == 0; - } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CURRENT)) { - current = atoi(&(line - [strlen - (PLAYLIST_STATE_FILE_CURRENT)])); - } else if (g_str_has_prefix(line, - PLAYLIST_STATE_FILE_PLAYLIST_BEGIN)) { - playlist_state_load(fp, buffer, playlist); - } - } - - playlist_set_random(playlist, pc, random_mode); - - if (!queue_is_empty(&playlist->queue)) { - if (!queue_valid_position(&playlist->queue, current)) - current = 0; - - if (state == PLAYER_STATE_PLAY && - config_get_bool("restore_paused", false)) - /* the user doesn't want MPD to auto-start - playback after startup; fall back to - "pause" */ - state = PLAYER_STATE_PAUSE; - - /* enable all devices for the first time; this must be - called here, after the audio output states were - restored, before playback begins */ - if (state != PLAYER_STATE_STOP) - pc_update_audio(pc); - - if (state == PLAYER_STATE_STOP /* && config_option */) - playlist->current = current; - else if (seek_time == 0) - playlist_play(playlist, pc, current); - else - playlist_seek_song(playlist, pc, current, seek_time); - - if (state == PLAYER_STATE_PAUSE) - pc_pause(pc); - } - - return true; -} - -unsigned -playlist_state_get_hash(const struct playlist *playlist, - struct player_control *pc) -{ - struct player_status player_status; - - pc_get_status(pc, &player_status); - - return playlist->queue.version ^ - (player_status.state != PLAYER_STATE_STOP - ? ((int)player_status.elapsed_time << 8) - : 0) ^ - (playlist->current >= 0 - ? (queue_order_to_position(&playlist->queue, - playlist->current) << 16) - : 0) ^ - ((int)pc_get_cross_fade(pc) << 20) ^ - (player_status.state << 24) ^ - (playlist->queue.random << 27) ^ - (playlist->queue.repeat << 28) ^ - (playlist->queue.single << 29) ^ - (playlist->queue.consume << 30) ^ - (playlist->queue.random << 31); -} diff --git a/src/playlist_state.h b/src/playlist_state.h deleted file mode 100644 index f67d01d2c..000000000 --- a/src/playlist_state.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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. - */ - -/* - * Saving and loading the playlist to/from the state file. - * - */ - -#ifndef PLAYLIST_STATE_H -#define PLAYLIST_STATE_H - -#include -#include -#include - -struct playlist; -struct player_control; - -void -playlist_state_save(FILE *fp, const struct playlist *playlist, - struct player_control *pc); - -bool -playlist_state_restore(const char *line, FILE *fp, GString *buffer, - struct playlist *playlist, struct player_control *pc); - -/** - * Generates a hash number for the current state of the playlist and - * the playback options. This is used by timer_save_state_file() to - * determine whether the state has changed and the state file should - * be saved. - */ -unsigned -playlist_state_get_hash(const struct playlist *playlist, - struct player_control *pc); - -#endif diff --git a/src/queue_save.c b/src/queue_save.c deleted file mode 100644 index 00b5ecbb1..000000000 --- a/src/queue_save.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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 "queue_save.h" -#include "queue.h" -#include "song.h" -#include "uri.h" -#include "database.h" -#include "song_save.h" -#include "text_file.h" - -#include - -#define PRIO_LABEL "Prio: " - -static void -queue_save_database_song(FILE *fp, int idx, const struct song *song) -{ - char *uri = song_get_uri(song); - - fprintf(fp, "%i:%s\n", idx, uri); - g_free(uri); -} - -static void -queue_save_full_song(FILE *fp, const struct song *song) -{ - song_save(fp, song); -} - -static void -queue_save_song(FILE *fp, int idx, const struct song *song) -{ - if (song_in_database(song)) - queue_save_database_song(fp, idx, song); - else - queue_save_full_song(fp, song); -} - -void -queue_save(FILE *fp, const struct queue *queue) -{ - for (unsigned i = 0; i < queue_length(queue); i++) { - uint8_t prio = queue_get_priority_at_position(queue, i); - if (prio != 0) - fprintf(fp, PRIO_LABEL "%u\n", prio); - - queue_save_song(fp, i, queue_get(queue, i)); - } -} - -static struct song * -get_song(const char *uri) -{ - return uri_has_scheme(uri) - ? song_remote_new(uri) - : db_get_song(uri); -} - -void -queue_load_song(FILE *fp, GString *buffer, const char *line, - struct queue *queue) -{ - struct song *song; - - if (queue_is_full(queue)) - return; - - uint8_t priority = 0; - if (g_str_has_prefix(line, PRIO_LABEL)) { - priority = strtoul(line + sizeof(PRIO_LABEL) - 1, NULL, 10); - - line = read_text_line(fp, buffer); - if (line == NULL) - return; - } - - if (g_str_has_prefix(line, SONG_BEGIN)) { - const char *uri = line + sizeof(SONG_BEGIN) - 1; - if (!uri_has_scheme(uri) && !g_path_is_absolute(uri)) - return; - - GError *error = NULL; - song = song_load(fp, NULL, uri, buffer, &error); - if (song == NULL) { - g_warning("%s", error->message); - g_error_free(error); - return; - } - } else { - char *endptr; - long ret = strtol(line, &endptr, 10); - if (ret < 0 || *endptr != ':' || endptr[1] == 0) { - g_warning("Malformed playlist line in state file"); - return; - } - - line = endptr + 1; - - song = get_song(line); - if (song == NULL) - return; - } - - queue_append(queue, song, priority); - - if (song_in_database(song)) - db_return_song(song); -} diff --git a/src/queue_save.h b/src/queue_save.h deleted file mode 100644 index 5526d615d..000000000 --- a/src/queue_save.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -/* - * This library saves the queue into the state file, and also loads it - * back into memory. - */ - -#ifndef QUEUE_SAVE_H -#define QUEUE_SAVE_H - -#include -#include - -struct queue; - -void -queue_save(FILE *fp, const struct queue *queue); - -/** - * Loads one song from the state file and appends it to the queue. - */ -void -queue_load_song(FILE *fp, GString *buffer, const char *line, - struct queue *queue); - -#endif diff --git a/src/song_save.c b/src/song_save.c deleted file mode 100644 index 4fcb46e22..000000000 --- a/src/song_save.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 "song_save.h" -#include "song.h" -#include "tag_save.h" -#include "directory.h" -#include "tag.h" -#include "text_file.h" -#include "string_util.h" - -#include - -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "song" - -#define SONG_MTIME "mtime" -#define SONG_END "song_end" - -static GQuark -song_save_quark(void) -{ - return g_quark_from_static_string("song_save"); -} - -void -song_save(FILE *fp, const struct song *song) -{ - fprintf(fp, SONG_BEGIN "%s\n", song->uri); - - if (song->end_ms > 0) - fprintf(fp, "Range: %u-%u\n", song->start_ms, song->end_ms); - else if (song->start_ms > 0) - fprintf(fp, "Range: %u-\n", song->start_ms); - - if (song->tag != NULL) - tag_save(fp, song->tag); - - fprintf(fp, SONG_MTIME ": %li\n", (long)song->mtime); - fprintf(fp, SONG_END "\n"); -} - -struct song * -song_load(FILE *fp, struct directory *parent, const char *uri, - GString *buffer, GError **error_r) -{ - struct song *song = parent != NULL - ? song_file_new(uri, parent) - : song_remote_new(uri); - char *line, *colon; - enum tag_type type; - const char *value; - - while ((line = read_text_line(fp, buffer)) != NULL && - strcmp(line, SONG_END) != 0) { - colon = strchr(line, ':'); - if (colon == NULL || colon == line) { - if (song->tag != NULL) - tag_end_add(song->tag); - song_free(song); - - g_set_error(error_r, song_save_quark(), 0, - "unknown line in db: %s", line); - return NULL; - } - - *colon++ = 0; - value = strchug_fast_c(colon); - - if ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) { - if (!song->tag) { - song->tag = tag_new(); - tag_begin_add(song->tag); - } - - tag_add_item(song->tag, type, value); - } else if (strcmp(line, "Time") == 0) { - if (!song->tag) { - song->tag = tag_new(); - tag_begin_add(song->tag); - } - - song->tag->time = atoi(value); - } else if (strcmp(line, "Playlist") == 0) { - if (!song->tag) { - song->tag = tag_new(); - tag_begin_add(song->tag); - } - - song->tag->has_playlist = strcmp(value, "yes") == 0; - } else if (strcmp(line, SONG_MTIME) == 0) { - song->mtime = atoi(value); - } else if (strcmp(line, "Range") == 0) { - char *endptr; - - song->start_ms = strtoul(value, &endptr, 10); - if (*endptr == '-') - song->end_ms = strtoul(endptr + 1, NULL, 10); - } else { - if (song->tag != NULL) - tag_end_add(song->tag); - song_free(song); - - g_set_error(error_r, song_save_quark(), 0, - "unknown line in db: %s", line); - return NULL; - } - } - - if (song->tag != NULL) - tag_end_add(song->tag); - - return song; -} diff --git a/src/song_save.h b/src/song_save.h deleted file mode 100644 index f6ecbbfeb..000000000 --- a/src/song_save.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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_SONG_SAVE_H -#define MPD_SONG_SAVE_H - -#include - -#include - -#define SONG_BEGIN "song_begin: " - -struct song; -struct directory; - -void -song_save(FILE *fp, const struct song *song); - -/** - * Loads a song from the input file. Reading stops after the - * "song_end" line. - * - * @param error_r location to store the error occurring, or NULL to - * ignore errors - * @return true on success, false on error - */ -struct song * -song_load(FILE *fp, struct directory *parent, const char *uri, - GString *buffer, GError **error_r); - -#endif diff --git a/src/state_file.c b/src/state_file.c deleted file mode 100644 index de0e70538..000000000 --- a/src/state_file.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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 "state_file.h" -#include "output_state.h" -#include "playlist.h" -#include "playlist_state.h" -#include "volume.h" -#include "text_file.h" - -#include -#include -#include -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "state_file" - -static char *state_file_path; - -/** the GLib source id for the save timer */ -static guint save_state_source_id; - -/** - * These version numbers determine whether we need to save the state - * file. If nothing has changed, we won't let the hard drive spin up. - */ -static unsigned prev_volume_version, prev_output_version, - prev_playlist_version; - -static void -state_file_write(struct player_control *pc) -{ - FILE *fp; - - assert(state_file_path != NULL); - - g_debug("Saving state file %s", state_file_path); - - fp = fopen(state_file_path, "w"); - if (G_UNLIKELY(!fp)) { - g_warning("failed to create %s: %s", - state_file_path, g_strerror(errno)); - return; - } - - save_sw_volume_state(fp); - audio_output_state_save(fp); - playlist_state_save(fp, &g_playlist, pc); - - fclose(fp); - - prev_volume_version = sw_volume_state_get_hash(); - prev_output_version = audio_output_state_get_version(); - prev_playlist_version = playlist_state_get_hash(&g_playlist, pc); -} - -static void -state_file_read(struct player_control *pc) -{ - FILE *fp; - bool success; - - assert(state_file_path != NULL); - - g_debug("Loading state file %s", state_file_path); - - fp = fopen(state_file_path, "r"); - if (G_UNLIKELY(!fp)) { - g_warning("failed to open %s: %s", - state_file_path, g_strerror(errno)); - return; - } - - GString *buffer = g_string_sized_new(1024); - const char *line; - while ((line = read_text_line(fp, buffer)) != NULL) { - success = read_sw_volume_state(line) || - audio_output_state_read(line) || - playlist_state_restore(line, fp, buffer, - &g_playlist, pc); - if (!success) - g_warning("Unrecognized line in state file: %s", line); - } - - fclose(fp); - - prev_volume_version = sw_volume_state_get_hash(); - prev_output_version = audio_output_state_get_version(); - prev_playlist_version = playlist_state_get_hash(&g_playlist, pc); - - - g_string_free(buffer, true); -} - -/** - * This function is called every 5 minutes by the GLib main loop, and - * saves the state file. - */ -static gboolean -timer_save_state_file(gpointer data) -{ - struct player_control *pc = data; - - if (prev_volume_version == sw_volume_state_get_hash() && - prev_output_version == audio_output_state_get_version() && - prev_playlist_version == playlist_state_get_hash(&g_playlist, pc)) - /* nothing has changed - don't save the state file, - don't spin up the hard disk */ - return true; - - state_file_write(pc); - return true; -} - -void -state_file_init(const char *path, struct player_control *pc) -{ - assert(state_file_path == NULL); - - if (path == NULL) - return; - - state_file_path = g_strdup(path); - state_file_read(pc); - - save_state_source_id = g_timeout_add_seconds(5 * 60, - timer_save_state_file, - pc); -} - -void -state_file_finish(struct player_control *pc) -{ - if (state_file_path == NULL) - /* no state file configured, no cleanup required */ - return; - - if (save_state_source_id != 0) - g_source_remove(save_state_source_id); - - state_file_write(pc); - - g_free(state_file_path); -} diff --git a/src/state_file.h b/src/state_file.h deleted file mode 100644 index 4c4f881cc..000000000 --- a/src/state_file.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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_STATE_FILE_H -#define MPD_STATE_FILE_H - -struct player_control; - -void -state_file_init(const char *path, struct player_control *pc); - -void -state_file_finish(struct player_control *pc); - -void write_state_file(void); - -#endif /* STATE_FILE_H */ diff --git a/src/tag_save.c b/src/tag_save.c deleted file mode 100644 index 2fdaef56c..000000000 --- a/src/tag_save.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 "tag_save.h" -#include "tag.h" -#include "tag_internal.h" -#include "song.h" - -void tag_save(FILE *file, const struct tag *tag) -{ - if (tag->time >= 0) - fprintf(file, SONG_TIME "%i\n", tag->time); - - if (tag->has_playlist) - fprintf(file, "Playlist: yes\n"); - - for (unsigned i = 0; i < tag->num_items; i++) - fprintf(file, "%s: %s\n", - tag_item_names[tag->items[i]->type], - tag->items[i]->value); -} diff --git a/src/tag_save.h b/src/tag_save.h deleted file mode 100644 index 9f6a580c8..000000000 --- a/src/tag_save.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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_TAG_SAVE_H -#define MPD_TAG_SAVE_H - -#include - -struct tag; - -void tag_save(FILE *file, const struct tag *tag); - -#endif diff --git a/test/DumpPlaylist.cxx b/test/DumpPlaylist.cxx new file mode 100644 index 000000000..231ae31a2 --- /dev/null +++ b/test/DumpPlaylist.cxx @@ -0,0 +1,255 @@ +/* + * 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 "TagSave.hxx" +#include "song.h" + +extern "C" { +#include "io_thread.h" +#include "input_init.h" +#include "input_stream.h" +#include "conf.h" +#include "decoder_api.h" +#include "decoder_list.h" +#include "playlist_list.h" +#include "playlist_plugin.h" +} + +#include + +#include +#include + +static void +my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level, + const gchar *message, G_GNUC_UNUSED gpointer user_data) +{ + if (log_domain != NULL) + g_printerr("%s: %s\n", log_domain, message); + else + g_printerr("%s\n", message); +} + +void +decoder_initialized(G_GNUC_UNUSED struct decoder *decoder, + G_GNUC_UNUSED const struct audio_format *audio_format, + G_GNUC_UNUSED bool seekable, + G_GNUC_UNUSED float total_time) +{ +} + +enum decoder_command +decoder_get_command(G_GNUC_UNUSED struct decoder *decoder) +{ + return DECODE_COMMAND_NONE; +} + +void +decoder_command_finished(G_GNUC_UNUSED struct decoder *decoder) +{ +} + +double +decoder_seek_where(G_GNUC_UNUSED struct decoder *decoder) +{ + return 1.0; +} + +void +decoder_seek_error(G_GNUC_UNUSED struct decoder *decoder) +{ +} + +size_t +decoder_read(G_GNUC_UNUSED struct decoder *decoder, + struct input_stream *is, + void *buffer, size_t length) +{ + return input_stream_lock_read(is, buffer, length, NULL); +} + +void +decoder_timestamp(G_GNUC_UNUSED struct decoder *decoder, + G_GNUC_UNUSED double t) +{ +} + +enum decoder_command +decoder_data(G_GNUC_UNUSED struct decoder *decoder, + G_GNUC_UNUSED struct input_stream *is, + const void *data, size_t datalen, + G_GNUC_UNUSED uint16_t kbit_rate) +{ + G_GNUC_UNUSED ssize_t nbytes = write(1, data, datalen); + return DECODE_COMMAND_NONE; +} + +enum decoder_command +decoder_tag(G_GNUC_UNUSED struct decoder *decoder, + G_GNUC_UNUSED struct input_stream *is, + G_GNUC_UNUSED const struct tag *tag) +{ + return DECODE_COMMAND_NONE; +} + +float +decoder_replay_gain(G_GNUC_UNUSED struct decoder *decoder, + const struct replay_gain_info *replay_gain_info) +{ + const struct replay_gain_tuple *tuple = + &replay_gain_info->tuples[REPLAY_GAIN_ALBUM]; + if (replay_gain_tuple_defined(tuple)) + g_printerr("replay_gain[album]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); + + tuple = &replay_gain_info->tuples[REPLAY_GAIN_TRACK]; + if (replay_gain_tuple_defined(tuple)) + g_printerr("replay_gain[track]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); + + return 0.0; +} + +void +decoder_mixramp(G_GNUC_UNUSED struct decoder *decoder, + G_GNUC_UNUSED float replay_gain_db, + char *mixramp_start, char *mixramp_end) +{ + g_free(mixramp_start); + g_free(mixramp_end); +} + +int main(int argc, char **argv) +{ + const char *uri; + struct input_stream *is = NULL; + bool success; + GError *error = NULL; + struct playlist_provider *playlist; + struct song *song; + + if (argc != 3) { + g_printerr("Usage: dump_playlist CONFIG URI\n"); + return 1; + } + + uri = argv[2]; + + /* initialize GLib */ + + g_thread_init(NULL); + g_log_set_default_handler(my_log_func, NULL); + + /* initialize MPD */ + + config_global_init(); + success = config_read_file(argv[1], &error); + if (!success) { + g_printerr("%s\n", error->message); + g_error_free(error); + return 1; + } + + io_thread_init(); + if (!io_thread_start(&error)) { + g_warning("%s", error->message); + g_error_free(error); + return EXIT_FAILURE; + } + + if (!input_stream_global_init(&error)) { + g_warning("%s", error->message); + g_error_free(error); + return 2; + } + + playlist_list_global_init(); + decoder_plugin_init_all(); + + /* open the playlist */ + + GMutex *mutex = g_mutex_new(); + GCond *cond = g_cond_new(); + + playlist = playlist_list_open_uri(uri, mutex, cond); + if (playlist == NULL) { + /* open the stream and wait until it becomes ready */ + + is = input_stream_open(uri, mutex, cond, &error); + if (is == NULL) { + if (error != NULL) { + g_warning("%s", error->message); + g_error_free(error); + } else + g_printerr("input_stream_open() failed\n"); + return 2; + } + + input_stream_lock_wait_ready(is); + + /* open the playlist */ + + playlist = playlist_list_open_stream(is, uri); + if (playlist == NULL) { + input_stream_close(is); + g_printerr("Failed to open playlist\n"); + return 2; + } + } + + /* dump the playlist */ + + while ((song = playlist_plugin_read(playlist)) != NULL) { + g_print("%s\n", song->uri); + + if (song->end_ms > 0) + g_print("range: %u:%02u..%u:%02u\n", + song->start_ms / 60000, + (song->start_ms / 1000) % 60, + song->end_ms / 60000, + (song->end_ms / 1000) % 60); + else if (song->start_ms > 0) + g_print("range: %u:%02u..\n", + song->start_ms / 60000, + (song->start_ms / 1000) % 60); + + if (song->tag != NULL) + tag_save(stdout, song->tag); + + song_free(song); + } + + /* deinitialize everything */ + + playlist_plugin_close(playlist); + if (is != NULL) + input_stream_close(is); + + g_cond_free(cond); + g_mutex_free(mutex); + + decoder_plugin_deinit_all(); + playlist_list_global_finish(); + input_stream_global_finish(); + io_thread_deinit(); + config_global_finish(); + + return 0; +} diff --git a/test/RunInput.cxx b/test/RunInput.cxx new file mode 100644 index 000000000..52b53db5a --- /dev/null +++ b/test/RunInput.cxx @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2003-2013 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 "TagSave.hxx" +#include "stdbin.h" + +extern "C" { +#include "io_thread.h" +#include "input_init.h" +#include "input_stream.h" +#include "tag.h" +#include "conf.h" + +#ifdef ENABLE_ARCHIVE +#include "archive_list.h" +#endif +} + +#include + +#include +#include + +static void +my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level, + const gchar *message, G_GNUC_UNUSED gpointer user_data) +{ + if (log_domain != NULL) + g_printerr("%s: %s\n", log_domain, message); + else + g_printerr("%s\n", message); +} + +static int +dump_input_stream(struct input_stream *is) +{ + GError *error = NULL; + char buffer[4096]; + size_t num_read; + ssize_t num_written; + + input_stream_lock(is); + + /* wait until the stream becomes ready */ + + input_stream_wait_ready(is); + + if (!input_stream_check(is, &error)) { + g_warning("%s", error->message); + g_error_free(error); + input_stream_unlock(is); + return EXIT_FAILURE; + } + + /* print meta data */ + + if (is->mime != NULL) + g_printerr("MIME type: %s\n", is->mime); + + /* read data and tags from the stream */ + + while (!input_stream_eof(is)) { + struct tag *tag = input_stream_tag(is); + if (tag != NULL) { + g_printerr("Received a tag:\n"); + tag_save(stderr, tag); + tag_free(tag); + } + + num_read = input_stream_read(is, buffer, sizeof(buffer), + &error); + if (num_read == 0) { + if (error != NULL) { + g_warning("%s", error->message); + g_error_free(error); + } + + break; + } + + num_written = write(1, buffer, num_read); + if (num_written <= 0) + break; + } + + if (!input_stream_check(is, &error)) { + g_warning("%s", error->message); + g_error_free(error); + input_stream_unlock(is); + return EXIT_FAILURE; + } + + input_stream_unlock(is); + + return 0; +} + +int main(int argc, char **argv) +{ + GError *error = NULL; + struct input_stream *is; + int ret; + + if (argc != 2) { + g_printerr("Usage: run_input URI\n"); + return 1; + } + + /* initialize GLib */ + + g_thread_init(NULL); + g_log_set_default_handler(my_log_func, NULL); + + /* initialize MPD */ + + config_global_init(); + + io_thread_init(); + if (!io_thread_start(&error)) { + g_warning("%s", error->message); + g_error_free(error); + return EXIT_FAILURE; + } + +#ifdef ENABLE_ARCHIVE + archive_plugin_init_all(); +#endif + + if (!input_stream_global_init(&error)) { + g_warning("%s", error->message); + g_error_free(error); + return 2; + } + + /* open the stream and dump it */ + + GMutex *mutex = g_mutex_new(); + GCond *cond = g_cond_new(); + + is = input_stream_open(argv[1], mutex, cond, &error); + if (is != NULL) { + ret = dump_input_stream(is); + input_stream_close(is); + } else { + if (error != NULL) { + g_warning("%s", error->message); + g_error_free(error); + } else + g_printerr("input_stream_open() failed\n"); + ret = 2; + } + + g_cond_free(cond); + g_mutex_free(mutex); + + /* deinitialize everything */ + + input_stream_global_finish(); + +#ifdef ENABLE_ARCHIVE + archive_plugin_deinit_all(); +#endif + + io_thread_deinit(); + + config_global_finish(); + + return ret; +} diff --git a/test/dump_playlist.c b/test/dump_playlist.c deleted file mode 100644 index 566872664..000000000 --- a/test/dump_playlist.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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 "io_thread.h" -#include "input_init.h" -#include "input_stream.h" -#include "tag_save.h" -#include "conf.h" -#include "song.h" -#include "decoder_api.h" -#include "decoder_list.h" -#include "playlist_list.h" -#include "playlist_plugin.h" - -#include - -#include -#include - -static void -my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level, - const gchar *message, G_GNUC_UNUSED gpointer user_data) -{ - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); -} - -void -decoder_initialized(G_GNUC_UNUSED struct decoder *decoder, - G_GNUC_UNUSED const struct audio_format *audio_format, - G_GNUC_UNUSED bool seekable, - G_GNUC_UNUSED float total_time) -{ -} - -enum decoder_command -decoder_get_command(G_GNUC_UNUSED struct decoder *decoder) -{ - return DECODE_COMMAND_NONE; -} - -void -decoder_command_finished(G_GNUC_UNUSED struct decoder *decoder) -{ -} - -double -decoder_seek_where(G_GNUC_UNUSED struct decoder *decoder) -{ - return 1.0; -} - -void -decoder_seek_error(G_GNUC_UNUSED struct decoder *decoder) -{ -} - -size_t -decoder_read(G_GNUC_UNUSED struct decoder *decoder, - struct input_stream *is, - void *buffer, size_t length) -{ - return input_stream_lock_read(is, buffer, length, NULL); -} - -void -decoder_timestamp(G_GNUC_UNUSED struct decoder *decoder, - G_GNUC_UNUSED double t) -{ -} - -enum decoder_command -decoder_data(G_GNUC_UNUSED struct decoder *decoder, - G_GNUC_UNUSED struct input_stream *is, - const void *data, size_t datalen, - G_GNUC_UNUSED uint16_t kbit_rate) -{ - G_GNUC_UNUSED ssize_t nbytes = write(1, data, datalen); - return DECODE_COMMAND_NONE; -} - -enum decoder_command -decoder_tag(G_GNUC_UNUSED struct decoder *decoder, - G_GNUC_UNUSED struct input_stream *is, - G_GNUC_UNUSED const struct tag *tag) -{ - return DECODE_COMMAND_NONE; -} - -float -decoder_replay_gain(G_GNUC_UNUSED struct decoder *decoder, - const struct replay_gain_info *replay_gain_info) -{ - const struct replay_gain_tuple *tuple = - &replay_gain_info->tuples[REPLAY_GAIN_ALBUM]; - if (replay_gain_tuple_defined(tuple)) - g_printerr("replay_gain[album]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); - - tuple = &replay_gain_info->tuples[REPLAY_GAIN_TRACK]; - if (replay_gain_tuple_defined(tuple)) - g_printerr("replay_gain[track]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); - - return 0.0; -} - -void -decoder_mixramp(G_GNUC_UNUSED struct decoder *decoder, - G_GNUC_UNUSED float replay_gain_db, - char *mixramp_start, char *mixramp_end) -{ - g_free(mixramp_start); - g_free(mixramp_end); -} - -int main(int argc, char **argv) -{ - const char *uri; - struct input_stream *is = NULL; - bool success; - GError *error = NULL; - struct playlist_provider *playlist; - struct song *song; - - if (argc != 3) { - g_printerr("Usage: dump_playlist CONFIG URI\n"); - return 1; - } - - uri = argv[2]; - - /* initialize GLib */ - - g_thread_init(NULL); - g_log_set_default_handler(my_log_func, NULL); - - /* initialize MPD */ - - config_global_init(); - success = config_read_file(argv[1], &error); - if (!success) { - g_printerr("%s\n", error->message); - g_error_free(error); - return 1; - } - - io_thread_init(); - if (!io_thread_start(&error)) { - g_warning("%s", error->message); - g_error_free(error); - return EXIT_FAILURE; - } - - if (!input_stream_global_init(&error)) { - g_warning("%s", error->message); - g_error_free(error); - return 2; - } - - playlist_list_global_init(); - decoder_plugin_init_all(); - - /* open the playlist */ - - GMutex *mutex = g_mutex_new(); - GCond *cond = g_cond_new(); - - playlist = playlist_list_open_uri(uri, mutex, cond); - if (playlist == NULL) { - /* open the stream and wait until it becomes ready */ - - is = input_stream_open(uri, mutex, cond, &error); - if (is == NULL) { - if (error != NULL) { - g_warning("%s", error->message); - g_error_free(error); - } else - g_printerr("input_stream_open() failed\n"); - return 2; - } - - input_stream_lock_wait_ready(is); - - /* open the playlist */ - - playlist = playlist_list_open_stream(is, uri); - if (playlist == NULL) { - input_stream_close(is); - g_printerr("Failed to open playlist\n"); - return 2; - } - } - - /* dump the playlist */ - - while ((song = playlist_plugin_read(playlist)) != NULL) { - g_print("%s\n", song->uri); - - if (song->end_ms > 0) - g_print("range: %u:%02u..%u:%02u\n", - song->start_ms / 60000, - (song->start_ms / 1000) % 60, - song->end_ms / 60000, - (song->end_ms / 1000) % 60); - else if (song->start_ms > 0) - g_print("range: %u:%02u..\n", - song->start_ms / 60000, - (song->start_ms / 1000) % 60); - - if (song->tag != NULL) - tag_save(stdout, song->tag); - - song_free(song); - } - - /* deinitialize everything */ - - playlist_plugin_close(playlist); - if (is != NULL) - input_stream_close(is); - - g_cond_free(cond); - g_mutex_free(mutex); - - decoder_plugin_deinit_all(); - playlist_list_global_finish(); - input_stream_global_finish(); - io_thread_deinit(); - config_global_finish(); - - return 0; -} diff --git a/test/run_input.c b/test/run_input.c deleted file mode 100644 index acf25a283..000000000 --- a/test/run_input.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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 "io_thread.h" -#include "input_init.h" -#include "input_stream.h" -#include "tag_save.h" -#include "tag.h" -#include "conf.h" -#include "stdbin.h" - -#ifdef ENABLE_ARCHIVE -#include "archive_list.h" -#endif - -#include - -#include -#include - -static void -my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level, - const gchar *message, G_GNUC_UNUSED gpointer user_data) -{ - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); -} - -static int -dump_input_stream(struct input_stream *is) -{ - GError *error = NULL; - char buffer[4096]; - size_t num_read; - ssize_t num_written; - - input_stream_lock(is); - - /* wait until the stream becomes ready */ - - input_stream_wait_ready(is); - - if (!input_stream_check(is, &error)) { - g_warning("%s", error->message); - g_error_free(error); - input_stream_unlock(is); - return EXIT_FAILURE; - } - - /* print meta data */ - - if (is->mime != NULL) - g_printerr("MIME type: %s\n", is->mime); - - /* read data and tags from the stream */ - - while (!input_stream_eof(is)) { - struct tag *tag = input_stream_tag(is); - if (tag != NULL) { - g_printerr("Received a tag:\n"); - tag_save(stderr, tag); - tag_free(tag); - } - - num_read = input_stream_read(is, buffer, sizeof(buffer), - &error); - if (num_read == 0) { - if (error != NULL) { - g_warning("%s", error->message); - g_error_free(error); - } - - break; - } - - num_written = write(1, buffer, num_read); - if (num_written <= 0) - break; - } - - if (!input_stream_check(is, &error)) { - g_warning("%s", error->message); - g_error_free(error); - input_stream_unlock(is); - return EXIT_FAILURE; - } - - input_stream_unlock(is); - - return 0; -} - -int main(int argc, char **argv) -{ - GError *error = NULL; - struct input_stream *is; - int ret; - - if (argc != 2) { - g_printerr("Usage: run_input URI\n"); - return 1; - } - - /* initialize GLib */ - - g_thread_init(NULL); - g_log_set_default_handler(my_log_func, NULL); - - /* initialize MPD */ - - config_global_init(); - - io_thread_init(); - if (!io_thread_start(&error)) { - g_warning("%s", error->message); - g_error_free(error); - return EXIT_FAILURE; - } - -#ifdef ENABLE_ARCHIVE - archive_plugin_init_all(); -#endif - - if (!input_stream_global_init(&error)) { - g_warning("%s", error->message); - g_error_free(error); - return 2; - } - - /* open the stream and dump it */ - - GMutex *mutex = g_mutex_new(); - GCond *cond = g_cond_new(); - - is = input_stream_open(argv[1], mutex, cond, &error); - if (is != NULL) { - ret = dump_input_stream(is); - input_stream_close(is); - } else { - if (error != NULL) { - g_warning("%s", error->message); - g_error_free(error); - } else - g_printerr("input_stream_open() failed\n"); - ret = 2; - } - - g_cond_free(cond); - g_mutex_free(mutex); - - /* deinitialize everything */ - - input_stream_global_finish(); - -#ifdef ENABLE_ARCHIVE - archive_plugin_deinit_all(); -#endif - - io_thread_deinit(); - - config_global_finish(); - - return ret; -} -- cgit v1.2.3