diff options
-rw-r--r-- | include/cru/common/Exception.h | 3 | ||||
-rw-r--r-- | include/cru/common/io/FileNotExistException.h | 19 | ||||
-rw-r--r-- | include/cru/common/io/OpenFileFlag.h | 12 | ||||
-rw-r--r-- | src/common/Base.cpp | 2 | ||||
-rw-r--r-- | src/common/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/common/io/CFileStream.cpp | 25 | ||||
-rw-r--r-- | src/common/io/FileNotExistException.cpp | 12 | ||||
-rw-r--r-- | src/common/io/OpenFileFlag.cpp | 19 |
8 files changed, 88 insertions, 5 deletions
diff --git a/include/cru/common/Exception.h b/include/cru/common/Exception.h index 6f458d35..d7e32a5a 100644 --- a/include/cru/common/Exception.h +++ b/include/cru/common/Exception.h @@ -20,6 +20,9 @@ class CRU_BASE_API Exception : public std::exception { const char* what() const noexcept override; + protected: + void SetMessage(String message) { message_ = std::move(message); } + private: String message_; mutable std::string utf8_message_; diff --git a/include/cru/common/io/FileNotExistException.h b/include/cru/common/io/FileNotExistException.h new file mode 100644 index 00000000..f49271b1 --- /dev/null +++ b/include/cru/common/io/FileNotExistException.h @@ -0,0 +1,19 @@ +#pragma once + +#include "../Base.h" +#include "../Exception.h" + +namespace cru::io { + class CRU_BASE_API FileNotExistException : public Exception { + public: + FileNotExistException(String path); + + CRU_DEFAULT_COPY(FileNotExistException) + CRU_DEFAULT_MOVE(FileNotExistException) + + ~FileNotExistException() override = default; + + private: + String path_; + }; +} diff --git a/include/cru/common/io/OpenFileFlag.h b/include/cru/common/io/OpenFileFlag.h index fd8b6e2c..4a5789fb 100644 --- a/include/cru/common/io/OpenFileFlag.h +++ b/include/cru/common/io/OpenFileFlag.h @@ -11,11 +11,14 @@ using OpenFileFlag = Bitmask<details::OpenFileFlagTag>; struct OpenFileFlags { /** * \brief for reading + * If the file does not exist, FileNotExistException should be thrown. */ static constexpr OpenFileFlag Read{0x1}; /** * \brief for writing + * If the file does not exist and Create is not specified, + * FileNotExistException should be thrown. */ static constexpr OpenFileFlag Write{0x2}; @@ -34,7 +37,8 @@ struct OpenFileFlags { /** * \brief when writing, if the file does not exist, create one - * Only effective for writing. + * Only effective for writing. When file does not exist, FileNotExistException + * will NOT be thrown and a new file will be created. */ static constexpr OpenFileFlag Create{0x10}; @@ -43,4 +47,10 @@ struct OpenFileFlags { */ static constexpr OpenFileFlag Exclusive{0x20}; }; + +/** + * Append, Truncate, Create must be used with Write. + * Append and Truncate must not be used together. + */ +bool CheckOpenFileFlag(OpenFileFlag flags); } // namespace cru::io diff --git a/src/common/Base.cpp b/src/common/Base.cpp index b6d39fef..ba4077b4 100644 --- a/src/common/Base.cpp +++ b/src/common/Base.cpp @@ -1,6 +1,6 @@ #include "cru/common/Base.h" -#include <stdexcept> +#include <exception> namespace cru { void UnreachableCode() { std::terminate(); } diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 2c7f28e0..6541f156 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(CruBase StringToNumberConverter.cpp StringUtil.cpp io/CFileStream.cpp + io/FileNotExistException.cpp io/Stream.cpp io/Resource.cpp io/MemoryStream.cpp diff --git a/src/common/io/CFileStream.cpp b/src/common/io/CFileStream.cpp index 68fb137d..133cd8f6 100644 --- a/src/common/io/CFileStream.cpp +++ b/src/common/io/CFileStream.cpp @@ -46,22 +46,41 @@ CFileStream::CFileStream(std::FILE* file, bool readable, bool writable, } namespace { -std::string ConvertOpenFileFlagToCFileFlag(OpenFileFlag flags) { +/** + * Generally the fopen will return a NULL ptr if the file does not exist. Then + * we must throw FileNotExistException. However, there are cases we have to + * check existence explicitly before. The case is OpenFileFlags::Write is + * specified but OpenFileFlags::Create is not, in which fopen usually create a + * new file automatically but we want a FileNotExistException to be thrown. + */ +std::string ConvertOpenFileFlagToCFileFlag(OpenFileFlag flags, + bool* explicit_check_exist) { + *explicit_check_exist = false; + std::string result; + bool need_read = flags & OpenFileFlags::Read; bool need_write = flags & OpenFileFlags::Write; - bool append = flags & OpenFileFlags::Append; if (!need_write) { // No need to write? The simplest + // Note even OpenFileFlags::Create is set, we still have to check exist. return "r"; } // Now we need writing. - if (!need_read) { + bool create = OpenFileFlags::Create; + + if (!create) { + *explicit_check_exist = true; } + bool append = flags & OpenFileFlags::Append; + + if (!need_read) { + return "w"; + } } } // namespace diff --git a/src/common/io/FileNotExistException.cpp b/src/common/io/FileNotExistException.cpp new file mode 100644 index 00000000..a2e1fdb1 --- /dev/null +++ b/src/common/io/FileNotExistException.cpp @@ -0,0 +1,12 @@ +#include "cru/common/io/FileNotExistException.h" + +#include "cru/common/Exception.h" +#include "cru/common/Format.h" + +#include <utility> + +namespace cru::io { + FileNotExistException::FileNotExistException(String path): Exception(), path_(std::move(path)) { + SetMessage(Format(u"File {} does not exist.", path_)); + } +} diff --git a/src/common/io/OpenFileFlag.cpp b/src/common/io/OpenFileFlag.cpp new file mode 100644 index 00000000..6b9957fe --- /dev/null +++ b/src/common/io/OpenFileFlag.cpp @@ -0,0 +1,19 @@ +#include "cru/common/io/OpenFileFlag.h" + +namespace cru::io { +bool CheckOpenFileFlag(OpenFileFlag flags) { + auto has = [flags](OpenFileFlag flag) { return flags & flag; }; + + if ((has(OpenFileFlags::Append) || has(OpenFileFlags::Truncate) || + has(OpenFileFlags::Create)) && + !has(OpenFileFlags::Write)) { + return false; + } + + if (has(OpenFileFlags::Truncate) && has(OpenFileFlags::Append)) { + return false; + } + + return true; +} +} // namespace cru::io |