From 404de2dfde39ca181db531427638f249c6e334e7 Mon Sep 17 00:00:00 2001 From: Dominick Allen Date: Mon, 23 Sep 2024 22:46:38 -0500 Subject: Expand CBinaryFile interface. --- CMakeLists.txt | 5 ++- include/fud_c_file.hpp | 48 +++++++++++++++++++++++--- source/fud_c_file.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 137 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d3e399..d5ebb4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,9 +50,12 @@ if (FUD_DOC) REQUIRED dot OPTIONAL_COMPONENTS mscgen dia) - doxygen_add_docs(docs + set(DOXYGEN_GENERATE_HTML YES) + set(DOXYGEN_GENERATE_MAN YES) + doxygen_add_docs(fudDocs include # CONFIG_FILE "Doxyfile" + Comment "Generate man pages and html" ) endif() diff --git a/include/fud_c_file.hpp b/include/fud_c_file.hpp index 281d216..b48e8a0 100644 --- a/include/fud_c_file.hpp +++ b/include/fud_c_file.hpp @@ -26,6 +26,7 @@ namespace fud { +/** \brief Access Modes for */ enum class CFileMode : uint8_t { ReadOnly, @@ -76,12 +77,35 @@ constexpr const char* CTextFileModeFromFlags(CFileMode mode) } } -enum class FileResult +enum class FileStatus { Success, + InvalidName, + InvalidArgument, + InvalidState, + NullPointer, Error, }; +static inline const char* FileStatusToString(FileStatus status) { + switch (status) { + case FileStatus::Success: + return "Success"; + case FileStatus::InvalidName: + return "InvalidName"; + case FileStatus::InvalidArgument: + return "InvalidArgument"; + case FileStatus::InvalidState: + return "InvalidState"; + case FileStatus::NullPointer: + return "NullPointer"; + case FileStatus::Error: + return "Error"; + default: + return "Unknown"; + } +} + class CBinaryFile { public: CBinaryFile(const String& filename, CFileMode mode); @@ -89,13 +113,29 @@ class CBinaryFile { CBinaryFile(const CBinaryFile& rhs) = delete; ~CBinaryFile(); CBinaryFile& operator=(const CBinaryFile& rhs) = delete; - FileResult open(); + FileStatus open(); void close(); const FILE* file() const; - FILE* file(); + [[nodiscard]] FILE* file(); + + [[nodiscard]] bool isOpen() const; + + [[nodiscard]] Result size() const; + + template + [[nodiscard]] FileStatus read(T& destination, size_t length); + + template + [[nodiscard]] FileStatus read(T& destination, size_t length, size_t offset); + + [[nodiscard]] FileStatus read(void* destination, size_t destinationSize, size_t length); + + [[nodiscard]] FileStatus read(void* destination, size_t destinationSize, size_t length, size_t offset); private: - String m_filename; + FileStatus reset() const; + + const String m_filename; String m_extraFlags{}; String m_mode; CFileMode m_modeFlags; diff --git a/source/fud_c_file.cpp b/source/fud_c_file.cpp index 24186bf..3d15431 100644 --- a/source/fud_c_file.cpp +++ b/source/fud_c_file.cpp @@ -38,10 +38,13 @@ CBinaryFile::~CBinaryFile() { close(); } -FileResult CBinaryFile::open() +FileStatus CBinaryFile::open() { + if (!m_filename.valid()) { + return FileStatus::InvalidName; + } m_file = fopen(m_filename.c_str(), m_mode.c_str()); - return m_file != nullptr ? FileResult::Success : FileResult::Error; + return m_file != nullptr ? FileStatus::Success : FileStatus::Error; } void CBinaryFile::close() @@ -62,4 +65,88 @@ FILE* CBinaryFile::file() return m_file; } +bool CBinaryFile::isOpen() const +{ + return m_file != nullptr; +} + +Result CBinaryFile::size() const +{ + using RetType = Result; + if (!isOpen()) { + return RetType::error(FileStatus::InvalidState); + } + + auto seekStatus = fseek(m_file, 0, SEEK_END); + if (seekStatus != 0) { + return RetType::error(FileStatus::Error); + } + + auto fileSizeResult = ftell(m_file); + if (fileSizeResult < 0) { + return RetType::error(FileStatus::Error); + } + + auto fileSize = static_cast(fileSizeResult); + + auto resetStatus = reset(); + if (resetStatus != FileStatus::Success) { + return RetType::error(resetStatus); + } + + return RetType::okay(fileSize); +} + +FileStatus CBinaryFile::read(void* destination, size_t destinationSize, size_t length) +{ + return read(destination, destinationSize, length, 0); +} + +FileStatus CBinaryFile::read(void* destination, size_t destinationSize, size_t length, size_t offset) +{ + if (length == 0) { + return FileStatus::Success; + } + + if (destination == nullptr) { + return FileStatus::NullPointer; + } + + if (offset > LONG_MAX || SIZE_MAX - offset < length || destinationSize < length) { + return FileStatus::InvalidArgument; + } + + auto fileSizeResult = size(); + if (fileSizeResult.isError()) { + return fileSizeResult.getError(); + } + + auto fileSize = fileSizeResult.getOkay(); + if (offset + length > fileSize) { + return FileStatus::InvalidArgument; + } + + auto seekResult = fseek(m_file, static_cast(offset), SEEK_SET); + if (seekResult != 0) { + return FileStatus::Error; + } + + auto* destPtr = static_cast(destination); + auto readResult = fread(destPtr, length, 1, m_file); + if (readResult != 1) { + static_cast(reset()); + return FileStatus::Error; + } + + return FileStatus::Success; +} + +FileStatus CBinaryFile::reset() const { + if (!isOpen()) { + return FileStatus::InvalidState; + } + auto result = fseek(m_file, 0, SEEK_SET); + return result == 0 ? FileStatus::Success : FileStatus::Error; +} + } // namespace fud -- cgit v1.2.3