diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/common/mptFileIO.h')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/common/mptFileIO.h | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/common/mptFileIO.h b/Src/external_dependencies/openmpt-trunk/common/mptFileIO.h new file mode 100644 index 00000000..5c0112ce --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/common/mptFileIO.h @@ -0,0 +1,398 @@ +/* + * mptFileIO.h + * ----------- + * Purpose: A wrapper around std::fstream, enforcing usage of mpt::PathString. + * Notes : You should only ever use these wrappers instead of plain std::fstream classes. + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#pragma once + +#include "openmpt/all/BuildSettings.hpp" + +#if defined(MPT_ENABLE_FILEIO) + +#include "mpt/io_read/filecursor_memory.hpp" +#include "mpt/io_read/filecursor_stdstream.hpp" + +#include "../common/mptString.h" +#include "../common/mptPathString.h" +#include "../common/FileReaderFwd.h" + +#if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) +#if MPT_GCC_AT_LEAST(9,1,0) +#include <filesystem> +#endif // MPT_GCC_AT_LEAST(9,1,0) +#endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR +#include <fstream> +#include <ios> +#include <ostream> +#include <streambuf> +#include <utility> + +#if MPT_COMPILER_MSVC +#include <cstdio> +#endif // !MPT_COMPILER_MSVC + +#ifdef MODPLUG_TRACKER +#if MPT_OS_WINDOWS +#include <windows.h> +#endif // MPT_OS_WINDOWS +#endif // MODPLUG_TRACKER + +#endif // MPT_ENABLE_FILEIO + + +OPENMPT_NAMESPACE_BEGIN + + +#if defined(MPT_ENABLE_FILEIO) + + +// Sets the NTFS compression attribute on the file or directory. +// Requires read and write permissions for already opened files. +// Returns true if the attribute has been set. +// In almost all cases, the return value should be ignored because most filesystems other than NTFS do not support compression. +#ifdef MODPLUG_TRACKER +#if MPT_OS_WINDOWS +bool SetFilesystemCompression(HANDLE hFile); +bool SetFilesystemCompression(int fd); +bool SetFilesystemCompression(const mpt::PathString &filename); +#endif // MPT_OS_WINDOWS +#endif // MODPLUG_TRACKER + + +namespace mpt +{ + +namespace detail +{ + +template<typename Tbase> +inline void fstream_open(Tbase & base, const mpt::PathString & filename, std::ios_base::openmode mode) +{ + #if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR) + #if MPT_GCC_AT_LEAST(9,1,0) + base.open(static_cast<std::filesystem::path>(filename.AsNative()), mode); + #else // !MPT_GCC_AT_LEAST(9,1,0) + // Warning: MinGW with GCC earlier than 9.1 detected. Standard library does neither provide std::fstream wchar_t overloads nor std::filesystem with wchar_t support. Unicode filename support is thus unavailable. + base.open(mpt::ToCharset(mpt::Charset::Locale, filename.AsNative()).c_str(), mode); + #endif // MPT_GCC_AT_LEAST(9,1,0) + #else // !MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR + base.open(filename.AsNativePrefixed().c_str(), mode); + #endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR +} + +} // namespace detail + +// We cannot rely on implicit conversion of mpt::PathString to std::filesystem::path when constructing std::fstream +// because of broken overload implementation in GCC libstdc++ 8, 9, 10. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95642 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90704 + +class fstream + : public std::fstream +{ +private: + typedef std::fstream Tbase; +public: + fstream() {} + fstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) + { + detail::fstream_open<Tbase>(*this, filename, mode); + } +#if MPT_COMPILER_MSVC +protected: + fstream(std::FILE * file) + : std::fstream(file) + { + } +#endif // MPT_COMPILER_MSVC +public: + void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) + { + detail::fstream_open<Tbase>(*this, filename, mode); + } + void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; + void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; +#if MPT_OS_WINDOWS + void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; + void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete; +#endif +}; + +class ifstream + : public std::ifstream +{ +private: + typedef std::ifstream Tbase; +public: + ifstream() {} + ifstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in) + { + detail::fstream_open<Tbase>(*this, filename, mode); + } +#if MPT_COMPILER_MSVC +protected: + ifstream(std::FILE * file) + : std::ifstream(file) + { + } +#endif // MPT_COMPILER_MSVC +public: + void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in) + { + detail::fstream_open<Tbase>(*this, filename, mode); + } + void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; + void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; +#if MPT_OS_WINDOWS + void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in) = delete; + void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in) = delete; +#endif +}; + +class ofstream + : public std::ofstream +{ +private: + typedef std::ofstream Tbase; +public: + ofstream() {} + ofstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::out) + { + detail::fstream_open<Tbase>(*this, filename, mode); + } +#if MPT_COMPILER_MSVC +protected: + ofstream(std::FILE * file) + : std::ofstream(file) + { + } +#endif // MPT_COMPILER_MSVC +public: + void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::out) + { + detail::fstream_open<Tbase>(*this, filename, mode); + } + void open(const char * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; + void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; +#if MPT_OS_WINDOWS + void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::out) = delete; + void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::out) = delete; +#endif +}; + +enum class FlushMode +{ + None = 0, // no explicit flushes at all + Single = 1, // explicitly flush higher-leverl API layers + Full = 2, // explicitly flush *all* layers, up to and including disk write caches +}; + +inline FlushMode FlushModeFromBool(bool flush) +{ + return flush ? FlushMode::Full : FlushMode::None; +} + +#ifdef MODPLUG_TRACKER + +class SafeOutputFile +{ +private: + FlushMode m_FlushMode; +#if MPT_COMPILER_MSVC + std::FILE *m_f = nullptr; +#else // !MPT_COMPILER_MSVC + mpt::ofstream m_s; +#endif // MPT_COMPILER_MSVC +#if MPT_COMPILER_MSVC + class FILEostream + : public mpt::ofstream + { + public: + FILEostream(std::FILE * file) + : mpt::ofstream(file) + { + return; + } + }; + FILEostream m_s; + static mpt::tstring convert_mode(std::ios_base::openmode mode, FlushMode flushMode); + std::FILE * internal_fopen(const mpt::PathString &filename, std::ios_base::openmode mode, FlushMode flushMode); +#endif // MPT_COMPILER_MSVC +public: + SafeOutputFile() = delete; + explicit SafeOutputFile(const mpt::PathString &filename, std::ios_base::openmode mode = std::ios_base::out, FlushMode flushMode = FlushMode::Full) + : m_FlushMode(flushMode) +#if MPT_COMPILER_MSVC + , m_s(internal_fopen(filename, mode | std::ios_base::out, flushMode)) +#else // !MPT_COMPILER_MSVC + , m_s(filename, mode) +#endif // MPT_COMPILER_MSVC + { + if(!stream().is_open()) + { + stream().setstate(mpt::ofstream::failbit); + } + } + mpt::ofstream& stream() + { + return m_s; + } + operator mpt::ofstream& () + { + return stream(); + } + const mpt::ofstream& stream() const + { + return m_s; + } + operator const mpt::ofstream& () const + { + return stream(); + } + operator bool() const + { + return stream() ? true : false; + } + bool operator!() const + { + return stream().operator!(); + } + ~SafeOutputFile() noexcept(false); +}; + +#endif // MODPLUG_TRACKER + + + +#ifdef MODPLUG_TRACKER + +// LazyFileRef is a simple reference to an on-disk file by the means of a +// filename which allows easy assignment of the whole file contents to and from +// byte buffers. +class LazyFileRef { +private: + const mpt::PathString m_Filename; +public: + LazyFileRef(const mpt::PathString &filename) + : m_Filename(filename) + { + return; + } +public: + LazyFileRef & operator = (const std::vector<std::byte> &data); + LazyFileRef & operator = (const std::vector<char> &data); + LazyFileRef & operator = (const std::string &data); + operator std::vector<std::byte> () const; + operator std::vector<char> () const; + operator std::string () const; +}; + +#endif // MODPLUG_TRACKER + + +} // namespace mpt + + +class InputFile +{ +private: + mpt::PathString m_Filename; + mpt::ifstream m_File; + bool m_IsValid; + bool m_IsCached; + std::vector<std::byte> m_Cache; +public: + InputFile(const mpt::PathString &filename, bool allowWholeFileCaching = false); + ~InputFile(); + bool IsValid() const; + bool IsCached() const; + mpt::PathString GetFilename() const; + std::istream& GetStream(); + mpt::const_byte_span GetCache(); +private: + bool Open(const mpt::PathString &filename, bool allowWholeFileCaching = false); +}; + + +template <typename Targ1> +inline FileCursor make_FileCursor(Targ1 &&arg1) +{ + return mpt::IO::make_FileCursor<mpt::PathString>(std::forward<Targ1>(arg1)); +} + +template <typename Targ1, typename Targ2> +inline FileCursor make_FileCursor(Targ1 &&arg1, Targ2 &&arg2) +{ + return mpt::IO::make_FileCursor<mpt::PathString>(std::forward<Targ1>(arg1), std::forward<Targ2>(arg2)); +} + + +// templated in order to reduce header inter-dependencies +class InputFile; +template <typename TInputFile, std::enable_if_t<std::is_same<TInputFile, InputFile>::value, bool> = true> +inline FileCursor make_FileCursor(TInputFile &file) +{ + if(!file.IsValid()) + { + return FileCursor(); + } + if(file.IsCached()) + { + return mpt::IO::make_FileCursor<mpt::PathString>(file.GetCache(), std::make_shared<mpt::PathString>(file.GetFilename())); + } else + { + return mpt::IO::make_FileCursor<mpt::PathString>(file.GetStream(), std::make_shared<mpt::PathString>(file.GetFilename())); + } +} + + +template <typename Targ1> +inline FileCursor GetFileReader(Targ1 &&arg1) +{ + return make_FileCursor(std::forward<Targ1>(arg1)); +} + + +template <typename Targ1, typename Targ2> +inline FileCursor GetFileReader(Targ1 &&arg1, Targ2 &&arg2) +{ + return make_FileCursor(std::forward<Targ1>(arg1), std::forward<Targ2>(arg2)); +} + + +#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS + +class OnDiskFileWrapper +{ + +private: + + mpt::PathString m_Filename; + bool m_IsTempFile; + +public: + + OnDiskFileWrapper(FileCursor& file, const mpt::PathString& fileNameExtension = P_("tmp")); + + ~OnDiskFileWrapper(); + +public: + + bool IsValid() const; + + mpt::PathString GetFilename() const; + +}; // class OnDiskFileWrapper + +#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS + + +#endif // MPT_ENABLE_FILEIO + + +OPENMPT_NAMESPACE_END + |