aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/common/mptFileIO.h
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/common/mptFileIO.h
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/common/mptFileIO.h')
-rw-r--r--Src/external_dependencies/openmpt-trunk/common/mptFileIO.h398
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
+