DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.6KB

  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. #ifndef DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED
  17. #define DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED
  18. #include "String.hpp"
  19. #include <cstdio>
  20. #ifdef DISTRHO_OS_WINDOWS
  21. # include <stringapiset.h>
  22. #else
  23. # include <cerrno>
  24. #endif
  25. START_NAMESPACE_DISTRHO
  26. // --------------------------------------------------------------------------------------------------------------------
  27. // filesystem related calls
  28. /*
  29. * Wrapper around `fopen` call, needed on Windows because its C standard functions use ASCII instead of UTF-8.
  30. */
  31. static inline
  32. FILE* d_fopen(const char* const pathname, const char* const mode)
  33. {
  34. #ifdef DISTRHO_OS_WINDOWS
  35. WCHAR lpathname[MAX_PATH];
  36. WCHAR lmode[4];
  37. if (MultiByteToWideChar(CP_UTF8, 0, pathname, -1, lpathname, ARRAY_SIZE(lpathname)) != 0 &&
  38. MultiByteToWideChar(CP_UTF8, 0, mode, -1, lmode, ARRAY_SIZE(lmode)) != 0)
  39. return _wfopen(lpathname, lmode);
  40. #endif
  41. return fopen(pathname, mode);
  42. }
  43. // --------------------------------------------------------------------------------------------------------------------
  44. // filesystem related classes
  45. /**
  46. Handy class to help write files in a safe way, which does:
  47. - open pathname + ".tmp" instead of opening a file directly (so partial writes are safe)
  48. - on close, flush data to disk and rename file to remove ".tmp"
  49. To use it, create a local variable (on the stack) and call ok() or manually check @a fd variable.
  50. @code
  51. if (const SafeFileWriter file("/path/to/file.txt"); file.ok())
  52. file.write("Success!");
  53. @endcode
  54. */
  55. struct SafeFileWriter
  56. {
  57. String filename;
  58. FILE* const fd;
  59. /**
  60. Constructor, opening @a pathname + ".tmp" for writing.
  61. */
  62. SafeFileWriter(const char* const pathname, const char* const mode = "w")
  63. : filename(pathname),
  64. fd(d_fopen(filename + ".tmp", mode))
  65. {
  66. #ifndef DISTRHO_OS_WINDOWS
  67. if (fd == nullptr)
  68. d_stderr2("failed to open '%s' for writing: %s", pathname, std::strerror(errno));
  69. #endif
  70. }
  71. /**
  72. Destructor, will flush file data contents, close and rename file.
  73. */
  74. ~SafeFileWriter()
  75. {
  76. if (fd == nullptr)
  77. return;
  78. std::fflush(fd);
  79. std::fclose(fd);
  80. std::rename(filename + ".tmp", filename);
  81. }
  82. /** Check if the file was opened successfully. */
  83. inline bool ok() const noexcept
  84. {
  85. return fd != nullptr;
  86. }
  87. /** Wrapper around `fwrite`, purely for convenience. */
  88. inline size_t write(const void* const ptr, const size_t size, const size_t nmemb = 1) const
  89. {
  90. return std::fwrite(ptr, size, nmemb, fd);
  91. }
  92. };
  93. // --------------------------------------------------------------------------------------------------------------------
  94. END_NAMESPACE_DISTRHO
  95. #endif // DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED