rpcs3/Utilities/File.h

435 lines
9.7 KiB
C
Raw Normal View History

2015-04-24 21:38:11 +00:00
#pragma once
2016-02-01 21:55:43 +00:00
#include <memory>
#include <string>
#include <vector>
#include <type_traits>
#include "types.h"
namespace fs
2015-04-24 21:38:11 +00:00
{
2016-02-01 21:55:43 +00:00
// File open mode flags
enum struct open_mode : u32
{
2016-02-01 21:55:43 +00:00
read,
write,
append,
create,
trunc,
excl,
};
2016-02-01 21:55:43 +00:00
constexpr mset<open_mode> read = open_mode::read; // Enable reading
constexpr mset<open_mode> write = open_mode::write; // Enable writing
constexpr mset<open_mode> append = open_mode::append; // Always append to the end of the file
constexpr mset<open_mode> create = open_mode::create; // Create file if it doesn't exist
constexpr mset<open_mode> trunc = open_mode::trunc; // Clear opened file if it's not empty
constexpr mset<open_mode> excl = open_mode::excl; // Failure if the file already exists (used with `create`)
constexpr mset<open_mode> rewrite = write + create + trunc;
// File seek mode
enum class seek_mode : u32
2016-01-05 23:52:48 +00:00
{
seek_set,
seek_cur,
seek_end,
};
2016-02-01 21:55:43 +00:00
constexpr auto seek_set = seek_mode::seek_set; // From beginning
constexpr auto seek_cur = seek_mode::seek_cur; // From current position
constexpr auto seek_end = seek_mode::seek_end; // From end
// File attributes (TODO)
2015-04-24 21:38:11 +00:00
struct stat_t
{
bool is_directory;
bool is_writable;
2015-04-25 19:15:53 +00:00
u64 size;
s64 atime;
s64 mtime;
s64 ctime;
2015-04-24 21:38:11 +00:00
};
2016-02-01 21:55:43 +00:00
// File handle base
struct file_base
{
virtual ~file_base() = default;
virtual stat_t stat() = 0;
virtual bool trunc(u64 length) = 0;
virtual u64 read(void* buffer, u64 size) = 0;
virtual u64 write(const void* buffer, u64 size) = 0;
virtual u64 seek(s64 offset, seek_mode whence) = 0;
virtual u64 size() = 0;
};
// Directory entry (TODO)
struct dir_entry : stat_t
{
std::string name;
};
// Directory handle base
struct dir_base
{
virtual ~dir_base() = default;
virtual bool read(dir_entry&) = 0;
virtual void rewind() = 0;
};
// Virtual device
struct device_base
{
virtual ~device_base() = default;
virtual bool stat(const std::string& path, stat_t& info) = 0;
virtual bool remove_dir(const std::string& path) = 0;
virtual bool create_dir(const std::string& path) = 0;
virtual bool rename(const std::string& from, const std::string& to) = 0;
virtual bool remove(const std::string& path) = 0;
virtual bool trunc(const std::string& path, u64 length) = 0;
virtual std::unique_ptr<file_base> open(const std::string& path, mset<open_mode> mode) = 0;
virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
};
// Get virtual device for specified path (nullptr for real path)
std::shared_ptr<device_base> get_virtual_device(const std::string& path);
// Set virtual device with specified name (nullptr for deletion)
std::shared_ptr<device_base> set_virtual_device(const std::string& root_name, const std::shared_ptr<device_base>&);
// Try to get parent directory (returns empty string on failure)
2016-01-05 23:52:48 +00:00
std::string get_parent_dir(const std::string& path);
// Get file information
2015-04-24 21:38:11 +00:00
bool stat(const std::string& path, stat_t& info);
// Check whether a file or a directory exists (not recommended, use is_file() or is_dir() instead)
2015-04-24 21:38:11 +00:00
bool exists(const std::string& path);
// Check whether the file exists and is NOT a directory
2016-01-05 23:52:48 +00:00
bool is_file(const std::string& path);
// Check whether the directory exists and is NOT a file
2016-01-05 23:52:48 +00:00
bool is_dir(const std::string& path);
// Delete empty directory
2016-01-05 23:52:48 +00:00
bool remove_dir(const std::string& path);
// Create directory
2016-01-05 23:52:48 +00:00
bool create_dir(const std::string& path);
// Create directories
2015-04-24 21:38:11 +00:00
bool create_path(const std::string& path);
// Rename (move) file or directory
2015-04-24 21:38:11 +00:00
bool rename(const std::string& from, const std::string& to);
// Copy file contents
2015-04-24 21:38:11 +00:00
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
// Delete file
2016-01-05 23:52:48 +00:00
bool remove_file(const std::string& path);
// Change file size (possibly appending zeros)
2016-01-05 23:52:48 +00:00
bool truncate_file(const std::string& path, u64 length);
2015-04-24 21:38:11 +00:00
class file final
2015-04-24 21:38:11 +00:00
{
2016-02-01 21:55:43 +00:00
std::unique_ptr<file_base> m_file;
2015-04-24 21:38:11 +00:00
2016-02-01 21:55:43 +00:00
[[noreturn]] void xnull() const;
[[noreturn]] void xfail() const;
2015-04-24 21:38:11 +00:00
public:
2016-02-01 21:55:43 +00:00
// Default constructor
2015-04-25 19:15:53 +00:00
file() = default;
2015-04-24 21:38:11 +00:00
2016-02-01 21:55:43 +00:00
// Open file with specified mode
explicit file(const std::string& path, mset<open_mode> mode = ::fs::read)
{
2016-01-05 23:52:48 +00:00
open(path, mode);
}
2015-04-24 21:38:11 +00:00
2016-02-01 21:55:43 +00:00
// Open file with specified mode
bool open(const std::string& path, mset<open_mode> mode = ::fs::read);
// Open memory for read
explicit file(const void* ptr, std::size_t size);
// Open vector
explicit file(std::vector<char>& vec);
// Check whether the handle is valid (opened file)
explicit operator bool() const
{
2016-02-01 21:55:43 +00:00
return m_file.operator bool();
}
2015-04-24 21:38:11 +00:00
2016-02-01 21:55:43 +00:00
// Close the file explicitly
void close()
{
2016-02-01 21:55:43 +00:00
m_file.reset();
}
2016-02-01 21:55:43 +00:00
void reset(std::unique_ptr<file_base>&& ptr)
{
2016-02-01 21:55:43 +00:00
m_file = std::move(ptr);
}
2015-04-24 21:38:11 +00:00
2016-02-01 21:55:43 +00:00
std::unique_ptr<file_base> release()
{
2016-02-01 21:55:43 +00:00
return std::move(m_file);
}
// Change file size (possibly appending zero bytes)
2016-02-01 21:55:43 +00:00
bool trunc(u64 length) const
{
if (!m_file) xnull();
return m_file->trunc(length);
}
// Get file information
2016-02-01 21:55:43 +00:00
stat_t stat() const
{
if (!m_file) xnull();
return m_file->stat();
}
2015-04-24 21:38:11 +00:00
// Read the data from the file and return the amount of data written in buffer
2016-02-01 21:55:43 +00:00
u64 read(void* buffer, u64 count) const
{
if (!m_file) xnull();
return m_file->read(buffer, count);
}
// Write the data to the file and return the amount of data actually written
2016-02-01 21:55:43 +00:00
u64 write(const void* buffer, u64 count) const
{
if (!m_file) xnull();
return m_file->write(buffer, count);
}
2016-02-01 21:55:43 +00:00
// Change current position, returns previous position
u64 seek(s64 offset, seek_mode whence = seek_set) const
{
if (!m_file) xnull();
return m_file->seek(offset, whence);
}
// Get file size
2016-02-01 21:55:43 +00:00
u64 size() const
{
if (!m_file) xnull();
return m_file->size();
}
// Get current position
u64 pos() const
{
if (!m_file) xnull();
return m_file->seek(0, seek_cur);
}
2016-01-05 23:52:48 +00:00
// Write std::string unconditionally
const file& write(const std::string& str) const
{
2016-02-01 21:55:43 +00:00
if (write(str.data(), str.size()) != str.size()) xfail();
return *this;
}
2016-01-05 23:52:48 +00:00
// Write POD unconditionally
template<typename T>
2016-01-05 23:52:48 +00:00
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const
{
2016-02-01 21:55:43 +00:00
if (write(std::addressof(data), sizeof(T)) != sizeof(T)) xfail();
return *this;
}
2016-01-05 23:52:48 +00:00
// Write POD std::vector unconditionally
template<typename T>
2016-01-05 23:52:48 +00:00
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const std::vector<T>& vec) const
{
2016-02-01 21:55:43 +00:00
if (write(vec.data(), vec.size() * sizeof(T)) != vec.size() * sizeof(T)) xfail();
return *this;
}
2016-01-05 23:52:48 +00:00
// Read std::string, size must be set by resize() method
bool read(std::string& str) const
{
return read(&str[0], str.size()) == str.size();
}
2016-01-05 23:52:48 +00:00
// Read POD, sizeof(T) is used
template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(T& data) const
{
return read(&data, sizeof(T)) == sizeof(T);
}
2016-01-05 23:52:48 +00:00
// Read POD std::vector, size must be set by resize() method
template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(std::vector<T>& vec) const
{
return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size();
}
2016-01-05 23:52:48 +00:00
// Read POD (experimental)
template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const
{
2016-01-05 23:52:48 +00:00
T result;
2016-02-01 21:55:43 +00:00
if (!read(result)) xfail();
return result;
}
2016-01-05 23:52:48 +00:00
// Read full file to std::string
std::string to_string() const
{
std::string result;
result.resize(size());
2016-02-01 21:55:43 +00:00
if (seek(0), !read(result)) xfail();
2016-01-05 23:52:48 +00:00
return result;
}
2016-01-26 18:13:36 +00:00
// Read full file to std::vector
template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, std::vector<T>> to_vector() const
{
std::vector<T> result;
result.resize(size() / sizeof(T));
2016-02-01 21:55:43 +00:00
if (seek(0), !read(result)) xfail();
2016-01-26 18:13:36 +00:00
return result;
}
};
2016-02-01 21:55:43 +00:00
class dir final
{
2016-02-01 21:55:43 +00:00
std::unique_ptr<dir_base> m_dir;
2016-01-05 23:52:48 +00:00
2016-02-01 21:55:43 +00:00
[[noreturn]] void xnull() const;
2016-01-05 23:52:48 +00:00
public:
2016-02-01 21:55:43 +00:00
dir() = default;
2016-01-05 23:52:48 +00:00
2016-02-01 21:55:43 +00:00
// Open dir handle
explicit dir(const std::string& path)
2016-01-05 23:52:48 +00:00
{
2016-02-01 21:55:43 +00:00
open(path);
2016-01-05 23:52:48 +00:00
}
2016-02-01 21:55:43 +00:00
// Open specified directory
bool open(const std::string& path);
2016-01-05 23:52:48 +00:00
2016-02-01 21:55:43 +00:00
// Check whether the handle is valid (opened directory)
explicit operator bool() const
{
2016-02-01 21:55:43 +00:00
return m_dir.operator bool();
}
2015-04-24 21:38:11 +00:00
2016-02-01 21:55:43 +00:00
// Close the directory explicitly
void close()
{
2016-02-01 21:55:43 +00:00
m_dir.reset();
}
2015-04-25 19:15:53 +00:00
2016-02-01 21:55:43 +00:00
void reset(std::unique_ptr<dir_base>&& ptr)
{
2016-02-01 21:55:43 +00:00
m_dir = std::move(ptr);
}
2016-02-01 21:55:43 +00:00
std::unique_ptr<dir_base> release()
{
2016-02-01 21:55:43 +00:00
return std::move(m_dir);
}
2016-02-01 21:55:43 +00:00
// Get next directory entry
bool read(dir_entry& out) const
{
2016-02-01 21:55:43 +00:00
if (!m_dir) xnull();
return m_dir->read(out);
}
2015-04-25 19:15:53 +00:00
2016-02-01 21:55:43 +00:00
// Reset to the beginning
void rewind() const
{
2016-02-01 21:55:43 +00:00
if (!m_dir) xnull();
return m_dir->rewind();
}
2015-04-25 19:15:53 +00:00
class iterator
{
dir* m_parent;
2016-02-01 21:55:43 +00:00
dir_entry m_entry;
public:
enum class mode
{
from_first,
from_current
};
iterator(dir* parent, mode mode_ = mode::from_first)
: m_parent(parent)
{
if (!m_parent)
{
return;
}
if (mode_ == mode::from_first)
{
2016-02-01 21:55:43 +00:00
m_parent->rewind();
}
2016-02-01 21:55:43 +00:00
if (!m_parent->read(m_entry))
{
m_parent = nullptr;
}
}
2016-02-01 21:55:43 +00:00
dir_entry& operator *()
{
return m_entry;
}
iterator& operator++()
{
*this = { m_parent, mode::from_current };
return *this;
}
bool operator !=(const iterator& rhs) const
{
return m_parent != rhs.m_parent;
}
};
iterator begin()
{
2016-02-01 21:55:43 +00:00
return{ m_dir ? this : nullptr };
}
iterator end()
{
return{ nullptr };
}
2015-04-25 19:15:53 +00:00
};
// Get configuration directory
2016-01-05 23:52:48 +00:00
const std::string& get_config_dir();
// Get executable directory
2016-01-05 23:52:48 +00:00
const std::string& get_executable_dir();
2016-02-01 21:55:43 +00:00
// Delete directory and all its contents recursively
void remove_all(const std::string& path);
// Get size of all files recursively
u64 get_dir_size(const std::string& path);
2015-04-25 19:15:53 +00:00
}