292 lines
7.6 KiB
C
292 lines
7.6 KiB
C
|
/*
|
||
|
* 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 "BuildSettings.h"
|
||
|
|
||
|
#if defined(MPT_ENABLE_FILEIO)
|
||
|
|
||
|
#include "../common/mptString.h"
|
||
|
#include "../common/mptPathString.h"
|
||
|
#include "../common/mptIO.h"
|
||
|
|
||
|
#include <fstream>
|
||
|
#include <ios>
|
||
|
#include <ostream>
|
||
|
#include <streambuf>
|
||
|
#include <utility>
|
||
|
|
||
|
#if MPT_COMPILER_MSVC
|
||
|
#include <cstdio>
|
||
|
#endif // !MPT_COMPILER_MSVC
|
||
|
|
||
|
#if MPT_COMPILER_MSVC
|
||
|
#include <stdio.h>
|
||
|
#endif // !MPT_COMPILER_MSVC
|
||
|
|
||
|
#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
|
||
|
{
|
||
|
|
||
|
#if MPT_COMPILER_GCC && MPT_OS_WINDOWS
|
||
|
// GCC C++ library has no wchar_t overloads
|
||
|
#define MPT_FSTREAM_DO_CONVERSIONS_ANSI
|
||
|
#endif
|
||
|
|
||
|
namespace detail
|
||
|
{
|
||
|
|
||
|
template<typename Tbase>
|
||
|
inline void fstream_open(Tbase & base, const mpt::PathString & filename, std::ios_base::openmode mode)
|
||
|
{
|
||
|
#if defined(MPT_FSTREAM_DO_CONVERSIONS_ANSI)
|
||
|
base.open(mpt::ToCharset(mpt::Charset::Locale, filename.AsNative()).c_str(), mode);
|
||
|
#else
|
||
|
base.open(filename.AsNativePrefixed().c_str(), mode);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
} // namespace detail
|
||
|
|
||
|
class SafeOutputFile;
|
||
|
|
||
|
class fstream
|
||
|
: public std::fstream
|
||
|
{
|
||
|
private:
|
||
|
typedef std::fstream Tbase;
|
||
|
public:
|
||
|
friend SafeOutputFile;
|
||
|
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);
|
||
|
}
|
||
|
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:
|
||
|
friend SafeOutputFile;
|
||
|
public:
|
||
|
ifstream() {}
|
||
|
ifstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in)
|
||
|
{
|
||
|
detail::fstream_open<Tbase>(*this, filename, mode);
|
||
|
}
|
||
|
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:
|
||
|
friend SafeOutputFile;
|
||
|
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(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
|
||
|
FILE *m_f = nullptr;
|
||
|
#endif // MPT_COMPILER_MSVC
|
||
|
mpt::ofstream m_s;
|
||
|
#if MPT_COMPILER_MSVC
|
||
|
static mpt::tstring convert_mode(std::ios_base::openmode mode, FlushMode flushMode);
|
||
|
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_IsCached;
|
||
|
std::vector<std::byte> m_Cache;
|
||
|
public:
|
||
|
static bool DefaultToLargeAddressSpaceUsage();
|
||
|
public:
|
||
|
InputFile();
|
||
|
InputFile(const mpt::PathString &filename, bool allowWholeFileCaching = DefaultToLargeAddressSpaceUsage());
|
||
|
~InputFile();
|
||
|
bool Open(const mpt::PathString &filename, bool allowWholeFileCaching = DefaultToLargeAddressSpaceUsage());
|
||
|
bool IsValid() const;
|
||
|
bool IsCached() const;
|
||
|
const mpt::PathString& GetFilenameRef() const;
|
||
|
std::istream* GetStream();
|
||
|
mpt::const_byte_span GetCache();
|
||
|
};
|
||
|
|
||
|
|
||
|
#endif // MPT_ENABLE_FILEIO
|
||
|
|
||
|
|
||
|
|
||
|
OPENMPT_NAMESPACE_END
|
||
|
|