Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
398
Src/external_dependencies/openmpt-trunk/common/mptFileIO.h
Normal file
398
Src/external_dependencies/openmpt-trunk/common/mptFileIO.h
Normal file
|
@ -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
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue