OXYGENHUB
◆ main openmsx / src / file / File.hh
4.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef FILE_HH
2
#define FILE_HH
3
4
#include "FileBase.hh"
5
#include "MappedFile.hh"
6
7
#include "zstring_view.hh"
8
9
#include <bit>
10
#include <cstdint>
11
#include <ctime>
12
#include <memory>
13
#include <span>
14
#include <type_traits>
15
16
namespace openmsx {
17
18
class File
19
{
20
public:
21
	enum class OpenMode : uint8_t {
22
		NORMAL,
23
		TRUNCATE,
24
		CREATE,
25
		PRE_CACHE,
26
	};
27
28
	/** Create a closed file handle.
29
	 * The only valid operations on such an object are is_open() and the
30
	 * move-assignment operator.
31
	 */
32
	File();
33
34
	/** Create file object and open underlying file.
35
	 * @param filename Name of the file to be opened.
36
	 * @param mode Mode to open the file in:
37
	 * @throws FileNotFoundException if file not found
38
	 * @throws FileException for other errors
39
	 */
40
	explicit File(zstring_view filename, OpenMode mode = OpenMode::NORMAL);
41
42
	/** This constructor maps very closely on the fopen() libc function.
43
	  * Compared to constructor above, it does not transparently
44
	  * uncompress files.
45
	  * @param filename Name of the file to be opened.
46
	  * @param mode Open mode, same meaning as in fopen(), but we assert
47
	  *             that it contains a 'b' character.
48
	  */
49
	File(zstring_view filename, const char* mode);
50
51
	File(File&& other) noexcept;
52
53
	/* Used by MemoryBufferFile. */
54
	explicit File(std::unique_ptr<FileBase> file_);
55
56
	~File();
57
58
	File& operator=(File&& other) noexcept;
59
60
	/** Return true iff this file handle refers to an open file. */
61
	[[nodiscard]] bool is_open() const { return file != nullptr; }
62
63
	/** Close the current file.
64
	 * Equivalent to assigning a default constructed value to this object.
65
	 */
66
	void close();
67
68
	/** Read from file.
69
	 * @param buffer Destination buffer
70
	 * @throws FileException
71
	 */
72
	void read(std::span<uint8_t> buffer);
73
74
	template<typename T>
75
	void read(std::span<T> buffer) {
76
		read(std::span<uint8_t>{std::bit_cast<uint8_t*>(buffer.data()), buffer.size_bytes()});
77
	}
78
79
	/** Write to file.
80
	 * @param buffer Source buffer
81
	 * @throws FileException
82
	 */
83
	void write(std::span<const uint8_t> buffer);
84
85
	template<typename T>
86
	void write(std::span<T> buffer) {
87
		write(std::span<const uint8_t>{std::bit_cast<const uint8_t*>(buffer.data()), buffer.size_bytes()});
88
	}
89
90
	/** Map file in memory.
91
	 *
92
	 * This returns a RAII object of type MappedFile<T>. And that makes the
93
	 * data available as a std::span<T>.
94
	 *
95
	 * T can be 'const' or 'non-const', prefer 'const' when possible.
96
	 * For a 'non-const T', changes to the buffer are not propagated back to
97
	 * the file (IOW it's a private, non-shared mapping).
98
	 *
99
	 * Optionally the requested buffer can have some 'extra' elements at the
100
	 * end. Initially the memory holding those extra elements is filled with
101
	 * zeros. This can be useful if e.g. you want to append a zero-
102
	 * terminator after the file. Often this implementation can do that
103
	 * without extra cost (so no need to allocate a buffer, read the file
104
	 * and add some zeros).
105
	 */
106
	template<typename T>
107
	[[nodiscard]] MappedFile<T> mmap(size_t extra = 0) {
108
		return MappedFile<T>(file->mmap(extra * sizeof(T), std::is_const_v<T>));
109
	}
110
111
	/** Returns the size of this file
112
	 * @result The size of this file
113
	 * @throws FileException
114
	 */
115
	[[nodiscard]] size_t getSize();
116
117
	/** Move read/write pointer to the specified position.
118
	 * @param pos Position in bytes from the beginning of the file.
119
	 * @throws FileException
120
	 */
121
	void seek(size_t pos);
122
123
	/** Get the current position of the read/write pointer.
124
	 * @result Position in bytes from the beginning of the file.
125
	 * @throws FileException
126
	 */
127
	[[nodiscard]] size_t getPos();
128
129
	/** Truncate file size. Enlarging file size always works, but
130
	 *  making file smaller doesn't work on some platforms (windows)
131
	 * @throws FileException
132
	 */
133
	void truncate(size_t size);
134
135
	/** Force a write of all buffered data to disk. There is no need to
136
	 *  call this function before destroying a File object.
137
	 */
138
	void flush();
139
140
	/** Get original filename for this file. Usually this returns an
141
	 *  empty string. Only for compressed files that store the original
142
	 *  name this can be non-empty.
143
	 * @result Original file name
144
	 * @throws FileException
145
	 */
146
	[[nodiscard]] zstring_view getOriginalName();
147
148
	/** Check if this file is readonly
149
	 * @result true iff file is readonly
150
	 * @throws FileException
151
	 */
152
	[[nodiscard]] bool isReadOnly() const;
153
154
	/** Get the date/time of last modification
155
	 * @throws FileException
156
	 */
157
	[[nodiscard]] time_t getModificationDate();
158
159
private:
160
	friend class LocalFileReference;
161
	/** This is an internal method used by LocalFileReference. */
162
	[[nodiscard]] bool isLocalFile() const;
163
164
	std::unique_ptr<FileBase> file;
165
};
166
167
} // namespace openmsx
168
169
#endif