From be06a60c45b6c423a9acc8be3fb5789f5cdea922 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 9 Feb 2025 18:47:05 +0100 Subject: [PATCH] Add some handy filesystem related code for plugins Signed-off-by: falkTX --- distrho/extra/Filesystem.hpp | 107 +++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 distrho/extra/Filesystem.hpp diff --git a/distrho/extra/Filesystem.hpp b/distrho/extra/Filesystem.hpp new file mode 100644 index 00000000..5826ed08 --- /dev/null +++ b/distrho/extra/Filesystem.hpp @@ -0,0 +1,107 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2025 Filipe Coelho + * + * Permission to use, copy, modify, and/or distribute this software for any purpose with + * or without fee is hereby granted, provided that the above copyright notice and this + * permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED +#define DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED + +#include "String.hpp" + +#include + +#ifdef DISTRHO_OS_WINDOWS +# include +#endif + +START_NAMESPACE_DISTRHO + +// -------------------------------------------------------------------------------------------------------------------- +// filesystem related calls + +/* + * Wrapper around `fopen` call, needed on Windows because its C standard functions use ASCII instead of UTF-8. + */ +static inline +FILE* d_fopen(const char* const pathname, const char* const mode) +{ + #ifdef DISTRHO_OS_WINDOWS + WCHAR lpathname[MAX_PATH]; + WCHAR lmode[4]; + if (MultiByteToWideChar(CP_UTF8, 0, pathname, -1, lpathname, ARRAY_SIZE(lpathname)) != 0 && + MultiByteToWideChar(CP_UTF8, 0, mode, -1, lmode, ARRAY_SIZE(lmode)) != 0) + return _wfopen(lpathname, lmode); + #endif + + return fopen(pathname, mode); +} + +// -------------------------------------------------------------------------------------------------------------------- +// filesystem related classes + +/** + Handy class to help write files in a safe way, which does: + - open pathname + ".tmp" instead of opening a file directly (so partial writes are safe) + - on close, flush data to disk and rename file to remove ".tmp" + + To use it, create a local variable (on the stack) and call ok() or manually check @a fd variable. + @code + if (const SafeFileWriter file("/path/to/file.txt"); file.ok()) + file.write("Success!"); + @endcode + */ +struct SafeFileWriter +{ + /** Parameters from the run function, adjusted for event sync */ + String filename; + FILE* const fd; + + /** + Constructor, opening @a pathname + ".tmp" for writing. + */ + SafeFileWriter(const char* const pathname, const char* const mode = "w") + : filename(pathname), + fd(d_fopen(filename + ".tmp", mode)) {} + + /** + Destructor, will flush file data contents, close and rename file. + */ + ~SafeFileWriter() + { + if (fd == nullptr) + return; + + std::fflush(fd); + std::fclose(fd); + std::rename(filename + ".tmp", filename); + } + + /** Check if the file was opened successfully. */ + inline bool ok() const noexcept + { + return fd != nullptr; + } + + /** Wrapper around `fwrite`, purely for convenience. */ + inline size_t write(const void* const ptr, const size_t size, const size_t nmemb = 1) const + { + return std::fwrite(ptr, size, nmemb, fd); + } +}; + +// -------------------------------------------------------------------------------------------------------------------- + +END_NAMESPACE_DISTRHO + +#endif // DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED