#pragma once #include #include #include #include #ifdef _WIN32 #ifndef NOMINMAX #define NOMINMAX #endif #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #endif namespace savedata { template inline bool replace_file_with(const std::filesystem::path& path, const void* data, std::size_t size, ReplaceOperation&& replace_operation) { const auto parent = path.parent_path(); std::error_code error; if (!parent.empty()) { std::filesystem::create_directories(parent, error); if (error) { return false; } } auto temporary = path; temporary += ".tmp"; const auto remove_temporary = [&temporary]() { std::error_code ignored; std::filesystem::remove(temporary, ignored); }; { std::ofstream file(temporary, std::ios::binary | std::ios::trunc); if (!file) { remove_temporary(); return false; } if (size != 0) { if (data == nullptr) { file.close(); remove_temporary(); return false; } file.write(static_cast(data), static_cast(size)); } file.flush(); if (!file) { file.close(); remove_temporary(); return false; } file.close(); if (!file) { remove_temporary(); return false; } } const bool replaced = replace_operation(temporary, path); if (!replaced) { remove_temporary(); } return replaced; } inline bool replace_file(const std::filesystem::path& path, const void* data, std::size_t size) { #ifdef _WIN32 return replace_file_with(path, data, size, [](const auto& temporary, const auto& destination) { return ::MoveFileExW(temporary.c_str(), destination.c_str(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) != 0; }); #else return replace_file_with(path, data, size, [](const auto& temporary, const auto& destination) { std::error_code error; std::filesystem::rename(temporary, destination, error); return !error; }); #endif } }