载入中...
搜索中...
未找到
File.cpp
浏览该文件的文档.
1
3
4#include <cstring>
5
6#include "common/Exception.h"
9
10namespace eve {
11namespace filesystem {
12
13static bool hack_setupWriteDirectory() {
14 if (auto* f = getModInst(filesystem,Filesystem))
15 return f->setupWriteDirectory();
16 return false;
17}
18
19namespace physfs {
20
21File::File(std::string filename)
22 : filename(filename), file(nullptr), mode("c"), bufferMode("none"), bufferSize(0) {}
23
25 if (mode != "c") close();
26}
27
28bool File::open(std::string mode) {
29 if (mode == "c") return true;
30
31 // Love-style aliases → PhysFS binary modes.
32 if (mode == "r") mode = "rb";
33 else if (mode == "w") mode = "wb";
34 else if (mode == "a") mode = "ab";
35
36 if (!PHYSFS_isInit()) throw Exception("PhysFS is not initialized.");
37
38 // File must exist if read mode.
39 if ((mode == "rb") && !PHYSFS_exists(filename.c_str()))
40 throw Exception("Could not open file %s. Does not exist.", filename.c_str());
41
42 // Check whether the write directory is set.
43 if ((mode == "ab" || mode == "wb") && (PHYSFS_getWriteDir() == nullptr) && !hack_setupWriteDirectory())
44 throw Exception("Could not set write directory.");
45
46 // File already open?
47 if (file != nullptr) return false;
48
49 PHYSFS_getLastErrorCode();
50 PHYSFS_File *handle = nullptr;
51
52 if (mode == "rb") handle = PHYSFS_openRead(filename.c_str());
53 else if (mode == "ab") handle = PHYSFS_openAppend(filename.c_str());
54 else if (mode == "wb") handle = PHYSFS_openWrite(filename.c_str());
55 else
56 throw Exception("Invalid file mode %s.", mode.c_str());
57
58 if (handle == nullptr) {
59 const char *err = PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
60 if (err == nullptr) err = "unknown error";
61 throw Exception("Could not open file %s (%s)", filename.c_str(), err);
62 }
63
64 file = handle;
65
66 this->mode = mode;
67
68 if (file != nullptr && !setBuffer(bufferMode, bufferSize)) {
69 // Revert to buffer defaults if we don't successfully set the buffer.
70 bufferMode = "none";
71 bufferSize = 0;
72 }
73
74 return (file != nullptr);
75}
76
78 if (file == nullptr || !PHYSFS_close(file)) return false;
79
80 mode = "c";
81 file = nullptr;
82
83 return true;
84}
85
86bool File::isOpen() const { return mode != "c" && file != nullptr; }
87
88int64_t File::getSize() {
89 // If the file is closed, open it to
90 // check the size.
91 if (file == nullptr) {
92 open("rb");
93 int64_t size = (int64_t)PHYSFS_fileLength(file);
94 close();
95 return size;
96 }
97
98 return (int64_t)PHYSFS_fileLength(file);
99}
100
101int64_t File::read(void *dst, int64_t size) {
102 if (!file || mode != "rb") throw Exception("File is not opened for reading.");
103
104 int64_t max = (int64_t)PHYSFS_fileLength(file);
105 int64_t cur = (int64_t)PHYSFS_tell(file);
106 if (max < 0 || cur < 0) throw Exception("Could not read from file.");
107 if (cur > max) return 0;
108
109 int64_t remaining = max - cur;
110 size = (size == ALL) ? remaining : size;
111 if (size > remaining) size = remaining;
112
113 if (size < 0) throw Exception("Invalid read size.");
114
115 return PHYSFS_readBytes(file, dst, (PHYSFS_uint64)size);
116}
117
118bool File::write(const void *data, int64_t size) {
119 if (!file || (mode != "wb" && mode != "ab")) throw Exception("File is not opened for writing.");
120
121 if (size < 0) throw Exception("Invalid write size.");
122
123 // Try to write.
124 int64_t written = PHYSFS_writeBytes(file, data, (PHYSFS_uint64)size);
125
126 // Check that correct amount of data was written.
127 if (written != size) return false;
128
129 // Manually flush the buffer in BUFFER_LINE mode if we find a newline.
130 if (bufferMode == "newline" && bufferSize > size) {
131 if (memchr(data, '\n', (size_t)size) != nullptr) flush();
132 }
133
134 return true;
135}
136
138 if (!file || (mode != "wb" && mode != "ab")) throw Exception("File is not opened for writing.");
139
140 return PHYSFS_flush(file) != 0;
141}
142
143#ifdef EVENGINE_WINDOWS
144inline bool test_eof(File *f, PHYSFS_File *) {
145 int64_t pos = f->tell();
146 int64_t size = f->getSize();
147 return pos == -1 || size == -1 || pos >= size;
148}
149#else
150inline bool test_eof(File *, PHYSFS_File *file) { return PHYSFS_eof(file); }
151#endif
152
153bool File::isEOF() { return file == nullptr || test_eof(this, file); }
154
155int64_t File::tell() {
156 if (file == nullptr) return -1;
157
158 return (int64_t)PHYSFS_tell(file);
159}
160
161bool File::seek(uint64_t pos) { return file != nullptr && PHYSFS_seek(file, (PHYSFS_uint64)pos) != 0; }
162
163bool File::setBuffer(std::string bufmode, int64_t size) {
164 if (size < 0) return false;
165
166 // If the file isn't open, we'll make sure the buffer values are set in
167 // File::open.
168 if (!isOpen()) {
169 bufferMode = bufmode;
170 bufferSize = size;
171 return true;
172 }
173
174 int ret = 1;
175 if (bufferMode == "newline" || bufferMode == "full") {
176 ret = PHYSFS_setBuffer(file, size);
177 } else {
178 ret = PHYSFS_setBuffer(file, 0);
179 size = 0;
180 }
181
182 if (ret == 0) return false;
183
184 bufferMode = bufmode;
185 bufferSize = size;
186
187 return true;
188}
189
190std::string File::getBuffer(int64_t &size) const {
191 size = bufferSize;
192 return bufferMode;
193}
194
195std::string File::getFilename() const { return filename; }
196
197std::string File::getMode() const { return mode; }
198
199} // namespace physfs
200} // namespace filesystem
201} // namespace eve
filesystem::File * file
#define getModInst(N, T)
Definition Module.h:36
float f
Light2D::Data * data
static const int64_t ALL
Used to indicate ALL data in a file.
Definition File.h:19
bool isEOF() override
Checks whether we are currently at end-of-file.
Definition File.cpp:153
std::string getFilename() const override
Gets the filename for this File, or empty string if none.
Definition File.cpp:195
std::string getMode() const override
Gets the current mode of the File.
Definition File.cpp:197
bool close() override
Closes the file.
Definition File.cpp:77
bool open(std::string mode) override
Opens the file in a certain mode.
Definition File.cpp:28
bool seek(uint64_t pos) override
Seeks to a certain position in the File.
Definition File.cpp:161
bool setBuffer(std::string bufmode, int64_t size) override
Sets the buffering mode for the file. When buffering is enabled,
Definition File.cpp:163
virtual ~File()
Destructor.
Definition File.cpp:24
File(std::string filename)
Constructs an File with the given ilename.
Definition File.cpp:21
bool write(const void *data, int64_t size) override
Writes data into the File.
Definition File.cpp:118
int64_t read(void *dst, int64_t size) override
Reads data into the destination buffer.
Definition File.cpp:101
bool flush() override
Flushes the currently buffered file data to disk. Only applicable in write mode.
Definition File.cpp:137
int64_t getSize() override
Gets the size of the file.
Definition File.cpp:88
int64_t tell() override
Gets the current position in the File.
Definition File.cpp:155
bool isOpen() const override
Gets whether the file is open.
Definition File.cpp:86
std::string getBuffer(int64_t &size) const override
Definition File.cpp:190
bool test_eof(File *, PHYSFS_File *file)
Definition File.cpp:150
Definition Build.cpp:11