2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-04-21 19:08:41 +00:00

chore: add TextFileCheckDirtyOutput to FileUtils

This commit is contained in:
Jan Laupetin
2026-03-05 18:55:27 +00:00
parent d469af2328
commit d80cdd9712
4 changed files with 161 additions and 152 deletions

View File

@@ -1,5 +1,6 @@
#include "FileUtils.h"
#include <cstring>
#include <sstream>
namespace fs = std::filesystem;
@@ -65,4 +66,108 @@ namespace utils
return true;
}
TextFileCheckDirtyOutput::TextFileCheckDirtyOutput(fs::path path)
: m_path(std::move(path)),
m_open(false),
m_has_existing_file(false)
{
}
TextFileCheckDirtyOutput::~TextFileCheckDirtyOutput()
{
Close();
}
bool TextFileCheckDirtyOutput::Open()
{
if (m_open)
return false;
auto parentFolder(m_path);
parentFolder.remove_filename();
create_directories(parentFolder);
m_has_existing_file = fs::is_regular_file(m_path);
if (!m_has_existing_file)
{
m_file_stream = std::ofstream(m_path, std::fstream::out | std::fstream::binary);
if (!m_file_stream.is_open())
return false;
}
m_open = true;
return true;
}
std::ostream& TextFileCheckDirtyOutput::Stream()
{
if (!m_has_existing_file)
return m_file_stream;
return m_memory;
}
TextFileCheckDirtyResult TextFileCheckDirtyOutput::Close()
{
if (!m_open)
return TextFileCheckDirtyResult::FAILURE;
m_open = false;
if (m_has_existing_file)
{
const auto renderedContent = std::move(m_memory).str();
m_memory = std::ostringstream();
if (!FileIsDirty(renderedContent))
return TextFileCheckDirtyResult::OUTPUT_WAS_UP_TO_DATE;
std::ofstream stream(m_path, std::fstream::out | std::fstream::binary);
if (!stream.is_open())
return TextFileCheckDirtyResult::FAILURE;
stream.write(renderedContent.data(), renderedContent.size());
stream.close();
}
return TextFileCheckDirtyResult::OUTPUT_WRITTEN;
}
[[nodiscard]] bool TextFileCheckDirtyOutput::FileIsDirty(const std::string& renderedContent) const
{
const auto fileSize = static_cast<size_t>(fs::file_size(m_path));
const size_t contentSize = renderedContent.size();
if (fileSize != contentSize)
return true;
std::ifstream oldFileStream(m_path, std::fstream::in | std::fstream::binary);
if (!oldFileStream.is_open())
return true;
char buffer[4096];
size_t currentContentOffset = 0;
while (currentContentOffset < contentSize)
{
const auto expectedReadCount = std::min<size_t>(sizeof(buffer), contentSize - currentContentOffset);
oldFileStream.read(buffer, expectedReadCount);
if (oldFileStream.gcount() != expectedReadCount)
{
oldFileStream.close();
return true;
}
if (memcmp(buffer, renderedContent.data() + currentContentOffset, expectedReadCount) != 0)
{
oldFileStream.close();
return true;
}
currentContentOffset += expectedReadCount;
}
oldFileStream.close();
return false;
}
} // namespace utils

View File

@@ -21,4 +21,36 @@ namespace utils
* \return \c true if the user input was valid and could be processed successfully, otherwise \c false.
*/
bool ParsePathsString(const std::string& pathsString, std::set<std::string>& output);
enum class TextFileCheckDirtyResult : std::uint8_t
{
OUTPUT_WRITTEN,
OUTPUT_WAS_UP_TO_DATE,
FAILURE
};
class TextFileCheckDirtyOutput final
{
public:
explicit TextFileCheckDirtyOutput(std::filesystem::path path);
~TextFileCheckDirtyOutput();
TextFileCheckDirtyOutput(const TextFileCheckDirtyOutput& other) = delete;
TextFileCheckDirtyOutput(TextFileCheckDirtyOutput&& other) noexcept = default;
TextFileCheckDirtyOutput& operator=(const TextFileCheckDirtyOutput& other) = delete;
TextFileCheckDirtyOutput& operator=(TextFileCheckDirtyOutput&& other) noexcept = default;
bool Open();
std::ostream& Stream();
TextFileCheckDirtyResult Close();
private:
[[nodiscard]] bool FileIsDirty(const std::string& renderedContent) const;
std::filesystem::path m_path;
bool m_open;
bool m_has_existing_file;
std::ofstream m_file_stream;
std::ostringstream m_memory;
};
} // namespace utils