Dusk Audio Framework
Loading...
Searching...
No Matches
Filesystem.hpp
1/*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef DAF_FILESYSTEM_UTILS_HPP_INCLUDED
18#define DAF_FILESYSTEM_UTILS_HPP_INCLUDED
19
20#include "String.hpp"
21
22#include <cstdio>
23
24#ifdef DAF_OS_WINDOWS
25# include <stringapiset.h>
26#else
27# include <cerrno>
28#endif
29
31
32// --------------------------------------------------------------------------------------------------------------------
33// filesystem related calls
34
35/*
36 * Wrapper around `fopen` call, needed on Windows because its C standard functions use ASCII instead of UTF-8.
37 */
38static inline
39FILE* d_fopen(const char* const pathname, const char* const mode)
40{
41 #ifdef DAF_OS_WINDOWS
42 WCHAR lpathname[MAX_PATH];
43 WCHAR lmode[4];
44 if (MultiByteToWideChar(CP_UTF8, 0, pathname, -1, lpathname, ARRAY_SIZE(lpathname)) != 0 &&
45 MultiByteToWideChar(CP_UTF8, 0, mode, -1, lmode, ARRAY_SIZE(lmode)) != 0)
46 return _wfopen(lpathname, lmode);
47 #endif
48
49 return fopen(pathname, mode);
50}
51
52// --------------------------------------------------------------------------------------------------------------------
53// filesystem related classes
54
55/**
56 Handy class to help write files in a safe way, which does:
57 - open pathname + ".tmp" instead of opening a file directly (so partial writes are safe)
58 - on close, flush data to disk and rename file to remove ".tmp"
59
60 To use it, create a local variable (on the stack) and call ok() or manually check @a fd variable.
61 @code
62 if (const SafeFileWriter file("/path/to/file.txt"); file.ok())
63 file.write("Success!");
64 @endcode
65 */
67{
68 String filename;
69 FILE* const fd;
70
71 /**
72 Constructor, opening @a pathname + ".tmp" for writing.
73 */
74 SafeFileWriter(const char* const pathname, const char* const mode = "w")
75 : filename(pathname),
76 fd(d_fopen(filename + ".tmp", mode))
77 {
78 #ifndef DAF_OS_WINDOWS
79 if (fd == nullptr)
80 d_stderr2("failed to open '%s' for writing: %s", pathname, std::strerror(errno));
81 #endif
82 }
83
84 /**
85 Destructor, will flush file data contents, close and rename file.
86 */
88 {
89 if (fd == nullptr)
90 return;
91
92 std::fflush(fd);
93 std::fclose(fd);
94 std::rename(filename + ".tmp", filename);
95 }
96
97 /** Check if the file was opened successfully. */
98 inline bool ok() const noexcept
99 {
100 return fd != nullptr;
101 }
102
103 /** Wrapper around `fwrite`, purely for convenience. */
104 inline size_t write(const void* const ptr, const size_t size, const size_t nmemb = 1) const
105 {
106 return std::fwrite(ptr, size, nmemb, fd);
107 }
108};
109
110// --------------------------------------------------------------------------------------------------------------------
111
113
114#endif // DAF_FILESYSTEM_UTILS_HPP_INCLUDED
Definition String.hpp:35
#define END_NAMESPACE_DAF
Definition DafInfo.hpp:996
#define START_NAMESPACE_DAF
Definition DafInfo.hpp:990
SafeFileWriter(const char *const pathname, const char *const mode="w")
Definition Filesystem.hpp:74
size_t write(const void *const ptr, const size_t size, const size_t nmemb=1) const
Definition Filesystem.hpp:104
bool ok() const noexcept
Definition Filesystem.hpp:98
~SafeFileWriter()
Definition Filesystem.hpp:87