pound-emu_pound/core/common/IoFile.h
Ronald Caesar 05c4f7025f Major project restructuring
Remove unecessary files and made the tree much more cleaner.

Signed-off-by: Ronald Caesar <github43132@proton.me>
2025-08-23 17:23:33 -04:00

231 lines
6.4 KiB
C++

// Copyright 2025 Xenon Emulator Project. All rights reserved.
#pragma once
#include <filesystem>
#include <span>
#include "Enum.h"
#include "PathUtil.h"
namespace Base::FS
{
enum class FileAccessMode
{
/**
* If the file at path exists, it opens the file for reading.
* If the file at path does not exist, it fails to open the file.
*/
Read = 1 << 0,
/**
* If the file at path exists, the existing contents of the file are erased.
* The empty file is then opened for writing.
* If the file at path does not exist, it creates and opens a new empty file for writing.
*/
Write = 1 << 1,
/**
* If the file at path exists, it opens the file for reading and writing.
* If the file at path does not exist, it fails to open the file.
*/
ReadWrite = Read | Write,
/**
* If the file at path exists, it opens the file for appending.
* If the file at path does not exist, it creates and opens a new empty file for appending.
*/
Append = 1 << 2,
/**
* If the file at path exists, it opens the file for both reading and appending.
* If the file at path does not exist, it creates and opens a new empty file for both
* reading and appending.
*/
ReadAppend = Read | Append
};
DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode)
enum class FileMode
{
BinaryMode,
TextMode
};
enum class FileShareFlag
{
ShareNone, // Provides exclusive access to the file.
ShareReadOnly, // Provides read only shared access to the file.
ShareWriteOnly, // Provides write only shared access to the file.
ShareReadWrite // Provides read and write shared access to the file.
};
enum class SeekOrigin : u32
{
SetOrigin, // Seeks from the start of the file.
CurrentPosition, // Seeks from the current file pointer position.
End // Seeks from the end of the file.
};
class IOFile final
{
public:
IOFile();
explicit IOFile(const std::string& path, FileAccessMode mode, FileMode type = FileMode::BinaryMode,
FileShareFlag flag = FileShareFlag::ShareReadOnly);
explicit IOFile(std::string_view path, FileAccessMode mode, FileMode type = FileMode::BinaryMode,
FileShareFlag flag = FileShareFlag::ShareReadOnly);
explicit IOFile(const fs::path& path, FileAccessMode mode, FileMode type = FileMode::BinaryMode,
FileShareFlag flag = FileShareFlag::ShareReadOnly);
~IOFile();
IOFile(const IOFile&) = delete;
IOFile& operator=(const IOFile&) = delete;
IOFile(IOFile&& other) noexcept;
IOFile& operator=(IOFile&& other) noexcept;
fs::path GetPath() const { return filePath; }
FileAccessMode GetAccessMode() const { return fileAccessMode; }
FileMode GetType() const { return fileType; }
bool IsOpen() const { return file != nullptr; }
uptr GetFileMapping();
int Open(const fs::path& path, FileAccessMode mode, FileMode type = FileMode::BinaryMode,
FileShareFlag flag = FileShareFlag::ShareReadOnly);
void Close();
void Unlink();
bool Flush() const;
bool Commit() const;
bool SetSize(u64 size) const;
u64 GetSize() const;
bool Seek(s64 offset, SeekOrigin origin = SeekOrigin::SetOrigin) const;
s64 Tell() const;
template <typename T>
size_t Read(T& data) const
{
if constexpr (std::contiguous_iterator<typename T::iterator>)
{
using ContiguousType = typename T::value_type;
static_assert(std::is_trivially_copyable_v<ContiguousType>, "Data type must be trivially copyable.");
return ReadSpan<ContiguousType>(data);
}
else
{
return ReadObject(data) ? 1 : 0;
}
}
template <typename T>
size_t Write(const T& data) const
{
if constexpr (std::contiguous_iterator<typename T::iterator>)
{
using ContiguousType = typename T::value_type;
static_assert(std::is_trivially_copyable_v<ContiguousType>, "Data type must be trivially copyable.");
return WriteSpan<ContiguousType>(data);
}
else
{
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
return WriteObject(data) ? 1 : 0;
}
}
template <typename T>
size_t ReadSpan(std::span<T> data) const
{
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
if (!IsOpen())
{
return 0;
}
return ReadRaw<T>(data.data(), data.size());
}
template <typename T>
size_t ReadRaw(void* data, size_t size) const
{
return std::fread(data, sizeof(T), size, file);
}
template <typename T>
size_t WriteSpan(std::span<const T> data) const
{
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
if (!IsOpen())
{
return 0;
}
return std::fwrite(data.data(), sizeof(T), data.size(), file);
}
template <typename T>
bool ReadObject(T& object) const
{
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
static_assert(!std::is_pointer_v<T>, "T must not be a pointer to an object.");
if (!IsOpen())
{
return false;
}
return std::fread(&object, sizeof(T), 1, file) == 1;
}
template <typename T>
size_t WriteRaw(const void* data, size_t size) const
{
return std::fwrite(data, sizeof(T), size, file);
}
template <typename T>
bool WriteObject(const T& object) const
{
static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
static_assert(!std::is_pointer_v<T>, "T must not be a pointer to an object.");
if (!IsOpen())
{
return false;
}
return std::fwrite(&object, sizeof(T), 1, file) == 1;
}
std::string ReadString(size_t length) const;
size_t WriteString(std::span<const char> string) const { return WriteSpan(string); }
static size_t WriteBytes(const fs::path path, const auto& data)
{
IOFile out(path, FileAccessMode::Write);
return out.Write(data);
}
private:
fs::path filePath{};
FileAccessMode fileAccessMode{};
FileMode fileType{};
std::FILE* file = nullptr;
uptr fileMapping = 0;
};
u64 GetDirectorySize(const fs::path& path);
} // namespace Base::FS