/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2018 martysama0134. All rights reserved. // // This code is licensed under the MIT License (MIT). // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // /////////////////////////////////////////////////////////////////////////////// #pragma once #include #include #include #ifdef _WIN32 #include #endif namespace msl { class file_ptr { std::FILE * m_ptr_{nullptr}; public: // constructor file_ptr() = default; explicit file_ptr(const std::string & fn, const char * mode = "r") : file_ptr(fn.c_str(), mode){}; explicit file_ptr(const char * filename, const char * mode = "r") { open(filename, mode); } #ifdef _WIN32 explicit file_ptr(const std::wstring& fn, const wchar_t* mode = L"r") : file_ptr(fn.c_str(), mode) {}; explicit file_ptr(const wchar_t * filename, const wchar_t * mode = L"r") { open(filename, mode); } #endif explicit file_ptr(std::FILE * ptr) { m_ptr_ = ptr; } // move constructor file_ptr(file_ptr && fp) noexcept { reset(fp.m_ptr_); fp.m_ptr_ = nullptr; } file_ptr & operator=(file_ptr && fp) noexcept { reset(fp.m_ptr_); fp.m_ptr_ = nullptr; return *this; } // copy constructor file_ptr(const file_ptr &) = delete; file_ptr & operator=(const file_ptr &) = delete; // destructor ~file_ptr() { reset(); } //! @brief *ptr std::FILE * operator*() const { return m_ptr_; } //! @brief if (!ptr) bool operator!() const { return !m_ptr_; } //! @brief ptr->elem std::FILE * operator->() const { return m_ptr_; } //! @brief if (ptr) explicit operator bool() const { return m_ptr_; } #ifdef MSL_FILE_PTR_ENABLE_IMPLICIT_CONVERSION //! @brief implicit std::FILE ptr conversion operator std::FILE *() const { return m_ptr_; } #endif //! @brief get the file ptr std::FILE * get() const { return m_ptr_; } //! @brief get the file ptr ref std::FILE *& get_ref() { return m_ptr_; } //! @brief get the file ptr pointer std::FILE ** get_ptr() { return &m_ptr_; } //! @brief close the file ptr and reset it void open(const std::string & fn, const char * mode = "r") { open(fn.c_str(), mode); } //! @brief close the file ptr and reset it void open(const char * filename, const char * mode = "r") { #ifdef _WIN32 fopen_s(&m_ptr_, filename, mode); #else m_ptr_ = std::fopen(filename, mode); #endif } #ifdef _WIN32 //! @brief close the file ptr and reset it void open(const std::wstring& fn, const wchar_t* mode = L"r") { open(fn.c_str(), mode); } //! @brief close the file ptr and reset it void open(const wchar_t* filename, const wchar_t* mode = L"r") { _wfopen_s(&m_ptr_, filename, mode); } //! @brief reset and reopen new file void reset(const std::wstring& fn, const wchar_t* mode = L"r") { reset(fn.c_str(), mode); } //! @brief reset and reopen new file void reset(const wchar_t* filename, const wchar_t* mode = L"r") { reset(); open(filename, mode); } #endif //! @brief alias of reset() void close() { reset(); } //! @brief swap two file_ptr void swap(file_ptr & fp) noexcept { std::swap(m_ptr_, fp.m_ptr_); } //! @brief reset and reopen new file void reset(const std::string & fn, const char * mode = "r") { reset(fn.c_str(), mode); } //! @brief reset and reopen new file void reset(const char * filename, const char * mode = "r") { reset(); open(filename, mode); } //! @brief reset and reassign new ownership void reset(std::FILE * ptr) { reset(); m_ptr_ = ptr; } //! @brief close the file and reset the ptr void reset() { if (m_ptr_) { std::fclose(m_ptr_); m_ptr_ = nullptr; } } //! @brief release the file ptr std::FILE * release() { const auto ptr = m_ptr_; m_ptr_ = nullptr; return ptr; } //! @brief return whether or not the file is open bool is_open() const { return m_ptr_; } //! @brief return the file size whether from the current position or from beginning std::size_t size(bool from_current = false) const { const auto cur = std::ftell(m_ptr_); // get current pos std::fseek(m_ptr_, 0, SEEK_END); // go to EOF const auto filesize = std::ftell(m_ptr_); // get filesize std::fseek(m_ptr_, cur, SEEK_SET); // go to current pos return from_current ? filesize - cur : filesize; } //! @brief return the file size from the current position; alias of size(true) std::size_t remain_size() const { return size(true); } //! @brief write into the file from byte vector void write(const std::vector & vec) const { std::fwrite(vec.data(), vec.size(), 1, m_ptr_); } //! @brief write into the file from c array void write(const void * buf, size_t size) const { std::fwrite(buf, size, 1, m_ptr_); } //! @brief write into the file from string void string_write(const std::string & str) const { std::fwrite(str.data(), str.size(), 1, m_ptr_); } //! @brief write into the file from zstring void string_write(const char * str) const { std::fwrite(str, std::strlen(str), 1, m_ptr_); } #ifdef _WIN32 //! @brief write into the file from wstring void string_write(const std::wstring& str) const { std::fwrite(str.data(), str.size(), 1, m_ptr_); } //! @brief write into the file from wchar void string_write(const wchar_t* str) const { std::fwrite(str, std::wcslen(str), 1, m_ptr_); } #endif //! @brief read the file from the current position as byte stream returning a vector std::vector read(std::size_t n = 0) const { if (n == 0) // 0 implies reading the whole remaining file n = this->remain_size(); std::vector buf(n); std::fread(buf.data(), 1, buf.size(), m_ptr_); return buf; } //! @brief read the file from the current position as byte stream using a buffer void read(void * buf, std::size_t n = 0) const { if (n == 0) // 0 implies reading the whole remaining file n = this->remain_size(); std::fread(buf, 1, n, m_ptr_); } //! @brief read the file from the current position returning null-terminated string std::string string_read(const std::size_t n = 0) const { auto vec = this->read(n); if (!vec.empty() && vec[vec.size() - 1] != '\0') // append EOS at the end of vector vec.emplace_back('\0'); return std::string(vec.begin(), vec.end()); // convert vector to string } //! @brief read the file from the current position using a null-terminated string buffer void string_read(char buf[], const std::size_t n = 0) const { this->read(buf, n); if (buf[n - 1] != '\0') buf[n - 1] = '\0'; } }; } // namespace msl