Commit 9fb351a1 authored by Max Kellermann's avatar Max Kellermann

*Save, *State: use the OutputStream API instead of FILE*

parent 0d0ccacd
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "PlaylistDatabase.hxx" #include "PlaylistDatabase.hxx"
#include "db/PlaylistVector.hxx" #include "db/PlaylistVector.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
...@@ -31,13 +32,13 @@ ...@@ -31,13 +32,13 @@
static constexpr Domain playlist_database_domain("playlist_database"); static constexpr Domain playlist_database_domain("playlist_database");
void void
playlist_vector_save(FILE *fp, const PlaylistVector &pv) playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv)
{ {
for (const PlaylistInfo &pi : pv) for (const PlaylistInfo &pi : pv)
fprintf(fp, PLAYLIST_META_BEGIN "%s\n" os.Format(PLAYLIST_META_BEGIN "%s\n"
"mtime: %li\n" "mtime: %li\n"
"playlist_end\n", "playlist_end\n",
pi.name.c_str(), (long)pi.mtime); pi.name.c_str(), (long)pi.mtime);
} }
bool bool
......
...@@ -22,16 +22,15 @@ ...@@ -22,16 +22,15 @@
#include "check.h" #include "check.h"
#include <stdio.h>
#define PLAYLIST_META_BEGIN "playlist_begin: " #define PLAYLIST_META_BEGIN "playlist_begin: "
class PlaylistVector; class PlaylistVector;
class BufferedOutputStream;
class TextFile; class TextFile;
class Error; class Error;
void void
playlist_vector_save(FILE *fp, const PlaylistVector &pv); playlist_vector_save(BufferedOutputStream &os, const PlaylistVector &pv);
bool bool
playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name, playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name,
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "TagSave.hxx" #include "TagSave.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "tag/TagBuilder.hxx" #include "tag/TagBuilder.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
...@@ -38,38 +39,38 @@ ...@@ -38,38 +39,38 @@
static constexpr Domain song_save_domain("song_save"); static constexpr Domain song_save_domain("song_save");
static void static void
range_save(FILE *file, unsigned start_ms, unsigned end_ms) range_save(BufferedOutputStream &os, unsigned start_ms, unsigned end_ms)
{ {
if (end_ms > 0) if (end_ms > 0)
fprintf(file, "Range: %u-%u\n", start_ms, end_ms); os.Format("Range: %u-%u\n", start_ms, end_ms);
else if (start_ms > 0) else if (start_ms > 0)
fprintf(file, "Range: %u-\n", start_ms); os.Format("Range: %u-\n", start_ms);
} }
void void
song_save(FILE *fp, const Song &song) song_save(BufferedOutputStream &os, const Song &song)
{ {
fprintf(fp, SONG_BEGIN "%s\n", song.uri); os.Format(SONG_BEGIN "%s\n", song.uri);
range_save(fp, song.start_ms, song.end_ms); range_save(os, song.start_ms, song.end_ms);
tag_save(fp, song.tag); tag_save(os, song.tag);
fprintf(fp, SONG_MTIME ": %li\n", (long)song.mtime); os.Format(SONG_MTIME ": %li\n", (long)song.mtime);
fprintf(fp, SONG_END "\n"); os.Format(SONG_END "\n");
} }
void void
song_save(FILE *fp, const DetachedSong &song) song_save(BufferedOutputStream &os, const DetachedSong &song)
{ {
fprintf(fp, SONG_BEGIN "%s\n", song.GetURI()); os.Format(SONG_BEGIN "%s\n", song.GetURI());
range_save(fp, song.GetStartMS(), song.GetEndMS()); range_save(os, song.GetStartMS(), song.GetEndMS());
tag_save(fp, song.GetTag()); tag_save(os, song.GetTag());
fprintf(fp, SONG_MTIME ": %li\n", (long)song.GetLastModified()); os.Format(SONG_MTIME ": %li\n", (long)song.GetLastModified());
fprintf(fp, SONG_END "\n"); os.Format(SONG_END "\n");
} }
DetachedSong * DetachedSong *
......
...@@ -20,21 +20,20 @@ ...@@ -20,21 +20,20 @@
#ifndef MPD_SONG_SAVE_HXX #ifndef MPD_SONG_SAVE_HXX
#define MPD_SONG_SAVE_HXX #define MPD_SONG_SAVE_HXX
#include <stdio.h>
#define SONG_BEGIN "song_begin: " #define SONG_BEGIN "song_begin: "
struct Song; struct Song;
struct Directory; struct Directory;
class DetachedSong; class DetachedSong;
class BufferedOutputStream;
class TextFile; class TextFile;
class Error; class Error;
void void
song_save(FILE *fp, const Song &song); song_save(BufferedOutputStream &os, const Song &song);
void void
song_save(FILE *fp, const DetachedSong &song); song_save(BufferedOutputStream &os, const DetachedSong &song);
/** /**
* Loads a song from the input file. Reading stops after the * Loads a song from the input file. Reading stops after the
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include "output/OutputState.hxx" #include "output/OutputState.hxx"
#include "queue/PlaylistState.hxx" #include "queue/PlaylistState.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "fs/output/FileOutputStream.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "Partition.hxx" #include "Partition.hxx"
#include "Instance.hxx" #include "Instance.hxx"
#include "mixer/Volume.hxx" #include "mixer/Volume.hxx"
...@@ -62,25 +64,35 @@ StateFile::IsModified() const ...@@ -62,25 +64,35 @@ StateFile::IsModified() const
partition.pc); partition.pc);
} }
inline void
StateFile::Write(BufferedOutputStream &os)
{
save_sw_volume_state(os);
audio_output_state_save(os, partition.outputs);
playlist_state_save(os, partition.playlist, partition.pc);
}
inline bool
StateFile::Write(OutputStream &os, Error &error)
{
BufferedOutputStream bos(os);
Write(bos);
return bos.Flush(error);
}
void void
StateFile::Write() StateFile::Write()
{ {
FormatDebug(state_file_domain, FormatDebug(state_file_domain,
"Saving state file %s", path_utf8.c_str()); "Saving state file %s", path_utf8.c_str());
FILE *fp = FOpen(path, FOpenMode::WriteText); Error error;
if (gcc_unlikely(!fp)) { FileOutputStream fos(path, error);
FormatErrno(state_file_domain, "failed to create %s", if (!fos.IsDefined() || !Write(fos, error) || !fos.Commit(error)) {
path_utf8.c_str()); LogError(error);
return; return;
} }
save_sw_volume_state(fp);
audio_output_state_save(fp, partition.outputs);
playlist_state_save(fp, partition.playlist, partition.pc);
fclose(fp);
RememberVersions(); RememberVersions();
} }
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <string> #include <string>
struct Partition; struct Partition;
class OutputStream;
class BufferedOutputStream;
class StateFile final : private TimeoutMonitor { class StateFile final : private TimeoutMonitor {
AllocatedPath path; AllocatedPath path;
...@@ -53,6 +55,9 @@ public: ...@@ -53,6 +55,9 @@ public:
void CheckModified(); void CheckModified();
private: private:
bool Write(OutputStream &os, Error &error);
void Write(BufferedOutputStream &os);
/** /**
* Save the current state versions for use with IsModified(). * Save the current state versions for use with IsModified().
*/ */
......
...@@ -20,19 +20,19 @@ ...@@ -20,19 +20,19 @@
#include "config.h" #include "config.h"
#include "TagSave.hxx" #include "TagSave.hxx"
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#define SONG_TIME "Time: " #define SONG_TIME "Time: "
void void
tag_save(FILE *file, const Tag &tag) tag_save(BufferedOutputStream &os, const Tag &tag)
{ {
if (tag.time >= 0) if (tag.time >= 0)
fprintf(file, SONG_TIME "%i\n", tag.time); os.Format(SONG_TIME "%i\n", tag.time);
if (tag.has_playlist) if (tag.has_playlist)
fprintf(file, "Playlist: yes\n"); os.Format("Playlist: yes\n");
for (const auto &i : tag) for (const auto &i : tag)
fprintf(file, "%s: %s\n", os.Format("%s: %s\n", tag_item_names[i.type], i.value);
tag_item_names[i.type], i.value);
} }
...@@ -20,11 +20,10 @@ ...@@ -20,11 +20,10 @@
#ifndef MPD_TAG_SAVE_HXX #ifndef MPD_TAG_SAVE_HXX
#define MPD_TAG_SAVE_HXX #define MPD_TAG_SAVE_HXX
#include <stdio.h>
struct Tag; struct Tag;
class BufferedOutputStream;
void void
tag_save(FILE *file, const Tag &tag); tag_save(BufferedOutputStream &os, const Tag &tag);
#endif #endif
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "db/DatabaseError.hxx" #include "db/DatabaseError.hxx"
#include "Directory.hxx" #include "Directory.hxx"
#include "DirectorySave.hxx" #include "DirectorySave.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "tag/TagSettings.h" #include "tag/TagSettings.h"
...@@ -49,20 +50,20 @@ static constexpr unsigned DB_FORMAT = 2; ...@@ -49,20 +50,20 @@ static constexpr unsigned DB_FORMAT = 2;
static constexpr unsigned OLDEST_DB_FORMAT = 1; static constexpr unsigned OLDEST_DB_FORMAT = 1;
void void
db_save_internal(FILE *fp, const Directory &music_root) db_save_internal(BufferedOutputStream &os, const Directory &music_root)
{ {
fprintf(fp, "%s\n", DIRECTORY_INFO_BEGIN); os.Format("%s\n", DIRECTORY_INFO_BEGIN);
fprintf(fp, DB_FORMAT_PREFIX "%u\n", DB_FORMAT); os.Format(DB_FORMAT_PREFIX "%u\n", DB_FORMAT);
fprintf(fp, "%s%s\n", DIRECTORY_MPD_VERSION, VERSION); os.Format("%s%s\n", DIRECTORY_MPD_VERSION, VERSION);
fprintf(fp, "%s%s\n", DIRECTORY_FS_CHARSET, GetFSCharset()); os.Format("%s%s\n", DIRECTORY_FS_CHARSET, GetFSCharset());
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
if (!ignore_tag_items[i]) if (!ignore_tag_items[i])
fprintf(fp, DB_TAG_PREFIX "%s\n", tag_item_names[i]); os.Format(DB_TAG_PREFIX "%s\n", tag_item_names[i]);
fprintf(fp, "%s\n", DIRECTORY_INFO_END); os.Format("%s\n", DIRECTORY_INFO_END);
directory_save(fp, music_root); directory_save(os, music_root);
} }
bool bool
......
...@@ -20,14 +20,13 @@ ...@@ -20,14 +20,13 @@
#ifndef MPD_DATABASE_SAVE_HXX #ifndef MPD_DATABASE_SAVE_HXX
#define MPD_DATABASE_SAVE_HXX #define MPD_DATABASE_SAVE_HXX
#include <stdio.h>
struct Directory; struct Directory;
class BufferedOutputStream;
class TextFile; class TextFile;
class Error; class Error;
void void
db_save_internal(FILE *file, const Directory &root); db_save_internal(BufferedOutputStream &os, const Directory &root);
bool bool
db_load_internal(TextFile &file, Directory &root, Error &error); db_load_internal(TextFile &file, Directory &root, Error &error);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "PlaylistDatabase.hxx" #include "PlaylistDatabase.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/NumberParser.hxx" #include "util/NumberParser.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
...@@ -70,37 +71,37 @@ ParseTypeString(const char *type) ...@@ -70,37 +71,37 @@ ParseTypeString(const char *type)
} }
void void
directory_save(FILE *fp, const Directory &directory) directory_save(BufferedOutputStream &os, const Directory &directory)
{ {
if (!directory.IsRoot()) { if (!directory.IsRoot()) {
const char *type = DeviceToTypeString(directory.device); const char *type = DeviceToTypeString(directory.device);
if (type != nullptr) if (type != nullptr)
fprintf(fp, DIRECTORY_TYPE "%s\n", type); os.Format(DIRECTORY_TYPE "%s\n", type);
if (directory.mtime != 0) if (directory.mtime != 0)
fprintf(fp, DIRECTORY_MTIME "%lu\n", os.Format(DIRECTORY_MTIME "%lu\n",
(unsigned long)directory.mtime); (unsigned long)directory.mtime);
fprintf(fp, "%s%s\n", DIRECTORY_BEGIN, directory.GetPath()); os.Format("%s%s\n", DIRECTORY_BEGIN, directory.GetPath());
} }
for (const auto &child : directory.children) { for (const auto &child : directory.children) {
fprintf(fp, DIRECTORY_DIR "%s\n", child.GetName()); os.Format(DIRECTORY_DIR "%s\n", child.GetName());
if (!child.IsMount()) if (!child.IsMount())
directory_save(fp, child); directory_save(os, child);
if (ferror(fp)) if (!os.Check())
return; return;
} }
for (const auto &song : directory.songs) for (const auto &song : directory.songs)
song_save(fp, song); song_save(os, song);
playlist_vector_save(fp, directory.playlists); playlist_vector_save(os, directory.playlists);
if (!directory.IsRoot()) if (!directory.IsRoot())
fprintf(fp, DIRECTORY_END "%s\n", directory.GetPath()); os.Format(DIRECTORY_END "%s\n", directory.GetPath());
} }
static bool static bool
......
...@@ -20,14 +20,13 @@ ...@@ -20,14 +20,13 @@
#ifndef MPD_DIRECTORY_SAVE_HXX #ifndef MPD_DIRECTORY_SAVE_HXX
#define MPD_DIRECTORY_SAVE_HXX #define MPD_DIRECTORY_SAVE_HXX
#include <stdio.h>
struct Directory; struct Directory;
class TextFile; class TextFile;
class BufferedOutputStream;
class Error; class Error;
void void
directory_save(FILE *fp, const Directory &directory); directory_save(BufferedOutputStream &os, const Directory &directory);
bool bool
directory_load(TextFile &file, Directory &directory, Error &error); directory_load(TextFile &file, Directory &directory, Error &error);
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include "db/DatabaseLock.hxx" #include "db/DatabaseLock.hxx"
#include "db/DatabaseError.hxx" #include "db/DatabaseError.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "fs/output/FileOutputStream.hxx"
#include "config/ConfigData.hxx" #include "config/ConfigData.hxx"
#include "fs/FileSystem.hxx" #include "fs/FileSystem.hxx"
#include "util/CharUtil.hxx" #include "util/CharUtil.hxx"
...@@ -366,22 +368,16 @@ SimpleDatabase::Save(Error &error) ...@@ -366,22 +368,16 @@ SimpleDatabase::Save(Error &error)
LogDebug(simple_db_domain, "writing DB"); LogDebug(simple_db_domain, "writing DB");
FILE *fp = FOpen(path, FOpenMode::WriteText); FileOutputStream fos(path, error);
if (!fp) { if (!fos.IsDefined())
error.FormatErrno("unable to write to db file \"%s\"",
path_utf8.c_str());
return false; return false;
}
db_save_internal(fp, *root); BufferedOutputStream bos(fos);
if (ferror(fp)) { db_save_internal(bos, *root);
error.SetErrno("Failed to write to database file");
fclose(fp);
return false;
}
fclose(fp); if (!bos.Flush(error) || !fos.Commit(error))
return false;
struct stat st; struct stat st;
if (StatFile(path, st)) if (StatFile(path, st))
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "system/PeriodClock.hxx" #include "system/PeriodClock.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <assert.h> #include <assert.h>
...@@ -110,9 +111,10 @@ read_sw_volume_state(const char *line, MultipleOutputs &outputs) ...@@ -110,9 +111,10 @@ read_sw_volume_state(const char *line, MultipleOutputs &outputs)
return true; return true;
} }
void save_sw_volume_state(FILE *fp) void
save_sw_volume_state(BufferedOutputStream &os)
{ {
fprintf(fp, SW_VOLUME_STATE "%u\n", volume_software_set); os.Format(SW_VOLUME_STATE "%u\n", volume_software_set);
} }
unsigned unsigned
......
...@@ -22,9 +22,8 @@ ...@@ -22,9 +22,8 @@
#include "Compiler.h" #include "Compiler.h"
#include <stdio.h>
class MultipleOutputs; class MultipleOutputs;
class BufferedOutputStream;
void void
InvalidateHardwareVolume(); InvalidateHardwareVolume();
...@@ -39,7 +38,8 @@ volume_level_change(MultipleOutputs &outputs, unsigned volume); ...@@ -39,7 +38,8 @@ volume_level_change(MultipleOutputs &outputs, unsigned volume);
bool bool
read_sw_volume_state(const char *line, MultipleOutputs &outputs); read_sw_volume_state(const char *line, MultipleOutputs &outputs);
void save_sw_volume_state(FILE *fp); void
save_sw_volume_state(BufferedOutputStream &os);
/** /**
* Generates a hash number for the current state of the software * Generates a hash number for the current state of the software
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "Internal.hxx" #include "Internal.hxx"
#include "Domain.hxx" #include "Domain.hxx"
#include "Log.hxx" #include "Log.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include <assert.h> #include <assert.h>
...@@ -38,13 +39,13 @@ ...@@ -38,13 +39,13 @@
unsigned audio_output_state_version; unsigned audio_output_state_version;
void void
audio_output_state_save(FILE *fp, const MultipleOutputs &outputs) audio_output_state_save(BufferedOutputStream &os,
const MultipleOutputs &outputs)
{ {
for (unsigned i = 0, n = outputs.Size(); i != n; ++i) { for (unsigned i = 0, n = outputs.Size(); i != n; ++i) {
const AudioOutput &ao = outputs.Get(i); const AudioOutput &ao = outputs.Get(i);
fprintf(fp, AUDIO_DEVICE_STATE "%d:%s\n", os.Format(AUDIO_DEVICE_STATE "%d:%s\n", ao.enabled, ao.name);
ao.enabled, ao.name);
} }
} }
......
...@@ -25,15 +25,15 @@ ...@@ -25,15 +25,15 @@
#ifndef MPD_OUTPUT_STATE_HXX #ifndef MPD_OUTPUT_STATE_HXX
#define MPD_OUTPUT_STATE_HXX #define MPD_OUTPUT_STATE_HXX
#include <stdio.h>
class MultipleOutputs; class MultipleOutputs;
class BufferedOutputStream;
bool bool
audio_output_state_read(const char *line, MultipleOutputs &outputs); audio_output_state_read(const char *line, MultipleOutputs &outputs);
void void
audio_output_state_save(FILE *fp, const MultipleOutputs &outputs); audio_output_state_save(BufferedOutputStream &os,
const MultipleOutputs &outputs);
/** /**
* Generates a version number for the current state of the audio * Generates a version number for the current state of the audio
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "Playlist.hxx" #include "Playlist.hxx"
#include "queue/QueueSave.hxx" #include "queue/QueueSave.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "PlayerControl.hxx" #include "PlayerControl.hxx"
#include "config/ConfigGlobal.hxx" #include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx" #include "config/ConfigOption.hxx"
...@@ -59,47 +60,45 @@ ...@@ -59,47 +60,45 @@
#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX #define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
void void
playlist_state_save(FILE *fp, const struct playlist &playlist, playlist_state_save(BufferedOutputStream &os, const struct playlist &playlist,
PlayerControl &pc) PlayerControl &pc)
{ {
const auto player_status = pc.GetStatus(); const auto player_status = pc.GetStatus();
fputs(PLAYLIST_STATE_FILE_STATE, fp); os.Write(PLAYLIST_STATE_FILE_STATE);
if (playlist.playing) { if (playlist.playing) {
switch (player_status.state) { switch (player_status.state) {
case PlayerState::PAUSE: case PlayerState::PAUSE:
fputs(PLAYLIST_STATE_FILE_STATE_PAUSE "\n", fp); os.Write(PLAYLIST_STATE_FILE_STATE_PAUSE "\n");
break; break;
default: default:
fputs(PLAYLIST_STATE_FILE_STATE_PLAY "\n", fp); os.Write(PLAYLIST_STATE_FILE_STATE_PLAY "\n");
} }
fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", os.Format(PLAYLIST_STATE_FILE_CURRENT "%i\n",
playlist.queue.OrderToPosition(playlist.current)); playlist.queue.OrderToPosition(playlist.current));
fprintf(fp, PLAYLIST_STATE_FILE_TIME "%i\n", os.Format(PLAYLIST_STATE_FILE_TIME "%i\n",
(int)player_status.elapsed_time); (int)player_status.elapsed_time);
} else { } else {
fputs(PLAYLIST_STATE_FILE_STATE_STOP "\n", fp); os.Write(PLAYLIST_STATE_FILE_STATE_STOP "\n");
if (playlist.current >= 0) if (playlist.current >= 0)
fprintf(fp, PLAYLIST_STATE_FILE_CURRENT "%i\n", os.Format(PLAYLIST_STATE_FILE_CURRENT "%i\n",
playlist.queue.OrderToPosition(playlist.current)); playlist.queue.OrderToPosition(playlist.current));
} }
fprintf(fp, PLAYLIST_STATE_FILE_RANDOM "%i\n", playlist.queue.random); os.Format(PLAYLIST_STATE_FILE_RANDOM "%i\n", playlist.queue.random);
fprintf(fp, PLAYLIST_STATE_FILE_REPEAT "%i\n", playlist.queue.repeat); os.Format(PLAYLIST_STATE_FILE_REPEAT "%i\n", playlist.queue.repeat);
fprintf(fp, PLAYLIST_STATE_FILE_SINGLE "%i\n", playlist.queue.single); os.Format(PLAYLIST_STATE_FILE_SINGLE "%i\n", playlist.queue.single);
fprintf(fp, PLAYLIST_STATE_FILE_CONSUME "%i\n", os.Format(PLAYLIST_STATE_FILE_CONSUME "%i\n", playlist.queue.consume);
playlist.queue.consume); os.Format(PLAYLIST_STATE_FILE_CROSSFADE "%i\n",
fprintf(fp, PLAYLIST_STATE_FILE_CROSSFADE "%i\n", (int)pc.GetCrossFade());
(int)pc.GetCrossFade()); os.Format(PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", pc.GetMixRampDb());
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", os.Format(PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n",
pc.GetMixRampDb()); pc.GetMixRampDelay());
fprintf(fp, PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n", os.Write(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n");
pc.GetMixRampDelay()); queue_save(os, playlist.queue);
fputs(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n", fp); os.Write(PLAYLIST_STATE_FILE_PLAYLIST_END "\n");
queue_save(fp, playlist.queue);
fputs(PLAYLIST_STATE_FILE_PLAYLIST_END "\n", fp);
} }
static void static void
......
...@@ -25,15 +25,14 @@ ...@@ -25,15 +25,14 @@
#ifndef MPD_PLAYLIST_STATE_HXX #ifndef MPD_PLAYLIST_STATE_HXX
#define MPD_PLAYLIST_STATE_HXX #define MPD_PLAYLIST_STATE_HXX
#include <stdio.h>
struct playlist; struct playlist;
struct PlayerControl; struct PlayerControl;
class TextFile; class TextFile;
class BufferedOutputStream;
class SongLoader; class SongLoader;
void void
playlist_state_save(FILE *fp, const playlist &playlist, playlist_state_save(BufferedOutputStream &os, const playlist &playlist,
PlayerControl &pc); PlayerControl &pc);
bool bool
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "SongLoader.hxx" #include "SongLoader.hxx"
#include "playlist/PlaylistSong.hxx" #include "playlist/PlaylistSong.hxx"
#include "fs/TextFile.hxx" #include "fs/TextFile.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
...@@ -36,40 +37,41 @@ ...@@ -36,40 +37,41 @@
#define PRIO_LABEL "Prio: " #define PRIO_LABEL "Prio: "
static void static void
queue_save_database_song(FILE *fp, int idx, const DetachedSong &song) queue_save_database_song(BufferedOutputStream &os,
int idx, const DetachedSong &song)
{ {
fprintf(fp, "%i:%s\n", idx, song.GetURI()); os.Format("%i:%s\n", idx, song.GetURI());
} }
static void static void
queue_save_full_song(FILE *fp, const DetachedSong &song) queue_save_full_song(BufferedOutputStream &os, const DetachedSong &song)
{ {
song_save(fp, song); song_save(os, song);
} }
static void static void
queue_save_song(FILE *fp, int idx, const DetachedSong &song) queue_save_song(BufferedOutputStream &os, int idx, const DetachedSong &song)
{ {
if (song.IsInDatabase() && if (song.IsInDatabase() &&
song.GetStartMS() == 0 && song.GetEndMS() == 0) song.GetStartMS() == 0 && song.GetEndMS() == 0)
/* use the brief format (just the URI) for "full" /* use the brief format (just the URI) for "full"
database songs */ database songs */
queue_save_database_song(fp, idx, song); queue_save_database_song(os, idx, song);
else else
/* use the long format (URI, range, tags) for the /* use the long format (URI, range, tags) for the
rest, so all metadata survives a MPD restart */ rest, so all metadata survives a MPD restart */
queue_save_full_song(fp, song); queue_save_full_song(os, song);
} }
void void
queue_save(FILE *fp, const Queue &queue) queue_save(BufferedOutputStream &os, const Queue &queue)
{ {
for (unsigned i = 0; i < queue.GetLength(); i++) { for (unsigned i = 0; i < queue.GetLength(); i++) {
uint8_t prio = queue.GetPriorityAtPosition(i); uint8_t prio = queue.GetPriorityAtPosition(i);
if (prio != 0) if (prio != 0)
fprintf(fp, PRIO_LABEL "%u\n", prio); os.Format(PRIO_LABEL "%u\n", prio);
queue_save_song(fp, i, queue.Get(i)); queue_save_song(os, i, queue.Get(i));
} }
} }
......
...@@ -25,14 +25,13 @@ ...@@ -25,14 +25,13 @@
#ifndef MPD_QUEUE_SAVE_HXX #ifndef MPD_QUEUE_SAVE_HXX
#define MPD_QUEUE_SAVE_HXX #define MPD_QUEUE_SAVE_HXX
#include <stdio.h>
struct Queue; struct Queue;
class BufferedOutputStream;
class TextFile; class TextFile;
class SongLoader; class SongLoader;
void void
queue_save(FILE *fp, const Queue &queue); queue_save(BufferedOutputStream &os, const Queue &queue);
/** /**
* Loads one song from the state file and appends it to the queue. * Loads one song from the state file and appends it to the queue.
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include "playlist/PlaylistRegistry.hxx" #include "playlist/PlaylistRegistry.hxx"
#include "playlist/PlaylistPlugin.hxx" #include "playlist/PlaylistPlugin.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "fs/output/StdioOutputStream.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "Log.hxx" #include "Log.hxx"
...@@ -40,6 +42,15 @@ ...@@ -40,6 +42,15 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
static void
tag_save(FILE *file, const Tag &tag)
{
StdioOutputStream sos(file);
BufferedOutputStream bos(sos);
tag_save(bos, tag);
bos.Flush();
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
const char *uri; const char *uri;
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "util/Error.hxx" #include "util/Error.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "Log.hxx" #include "Log.hxx"
#include "fs/output/BufferedOutputStream.hxx"
#include "fs/output/StdioOutputStream.hxx"
#ifdef ENABLE_ARCHIVE #ifdef ENABLE_ARCHIVE
#include "archive/ArchiveList.hxx" #include "archive/ArchiveList.hxx"
...@@ -40,6 +42,15 @@ ...@@ -40,6 +42,15 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
static void
tag_save(FILE *file, const Tag &tag)
{
StdioOutputStream sos(file);
BufferedOutputStream bos(sos);
tag_save(bos, tag);
bos.Flush();
}
static int static int
dump_input_stream(InputStream *is) dump_input_stream(InputStream *is)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment