Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/nall/file.hpp
2 views
1
#ifndef NALL_FILE_HPP
2
#define NALL_FILE_HPP
3
4
#include <nall/platform.hpp>
5
#include <nall/stdint.hpp>
6
#include <nall/string.hpp>
7
#include <nall/utility.hpp>
8
#include <nall/windows/utf8.hpp>
9
10
namespace nall {
11
inline FILE* fopen_utf8(const string &utf8_filename, const char *mode) {
12
#if !defined(_WIN32)
13
return fopen(utf8_filename, mode);
14
#else
15
return _wfopen(utf16_t(utf8_filename), utf16_t(mode));
16
#endif
17
}
18
19
class file {
20
public:
21
enum class mode : unsigned { read, write, readwrite, writeread };
22
enum class index : unsigned { absolute, relative };
23
enum class time : unsigned { create, modify, access };
24
25
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
26
data = 0;
27
file fp;
28
if(fp.open(filename, mode::read) == false) return false;
29
size = fp.size();
30
data = new uint8_t[size];
31
fp.read(data, size);
32
fp.close();
33
return true;
34
}
35
36
static bool read(const string &filename, const uint8_t *&data, unsigned &size) {
37
return file::read(filename, (uint8_t*&)data, size);
38
}
39
40
static bool write(const string &filename, const uint8_t *data, unsigned size) {
41
file fp;
42
if(fp.open(filename, mode::write) == false) return false;
43
fp.write(data, size);
44
fp.close();
45
return true;
46
}
47
48
uint8_t read() {
49
if(!fp) return 0xff; //file not open
50
if(file_mode == mode::write) return 0xff; //reads not permitted
51
if(file_offset >= file_size) return 0xff; //cannot read past end of file
52
buffer_sync();
53
return buffer[(file_offset++) & buffer_mask];
54
}
55
56
uintmax_t readl(unsigned length = 1) {
57
uintmax_t data = 0;
58
for(int i = 0; i < length; i++) {
59
data |= (uintmax_t)read() << (i << 3);
60
}
61
return data;
62
}
63
64
uintmax_t readm(unsigned length = 1) {
65
uintmax_t data = 0;
66
while(length--) {
67
data <<= 8;
68
data |= read();
69
}
70
return data;
71
}
72
73
void read(uint8_t *buffer, unsigned length) {
74
while(length--) *buffer++ = read();
75
}
76
77
void write(uint8_t data) {
78
if(!fp) return; //file not open
79
if(file_mode == mode::read) return; //writes not permitted
80
buffer_sync();
81
buffer[(file_offset++) & buffer_mask] = data;
82
buffer_dirty = true;
83
if(file_offset > file_size) file_size = file_offset;
84
}
85
86
void writel(uintmax_t data, unsigned length = 1) {
87
while(length--) {
88
write(data);
89
data >>= 8;
90
}
91
}
92
93
void writem(uintmax_t data, unsigned length = 1) {
94
for(int i = length - 1; i >= 0; i--) {
95
write(data >> (i << 3));
96
}
97
}
98
99
void write(const uint8_t *buffer, unsigned length) {
100
while(length--) write(*buffer++);
101
}
102
103
template<typename... Args> void print(Args... args) {
104
string data(args...);
105
const char *p = data;
106
while(*p) write(*p++);
107
}
108
109
void flush() {
110
buffer_flush();
111
fflush(fp);
112
}
113
114
void seek(int offset, index index_ = index::absolute) {
115
if(!fp) return; //file not open
116
buffer_flush();
117
118
uintmax_t req_offset = file_offset;
119
switch(index_) {
120
case index::absolute: req_offset = offset; break;
121
case index::relative: req_offset += offset; break;
122
}
123
124
if(req_offset < 0) req_offset = 0; //cannot seek before start of file
125
if(req_offset > file_size) {
126
if(file_mode == mode::read) { //cannot seek past end of file
127
req_offset = file_size;
128
} else { //pad file to requested location
129
file_offset = file_size;
130
while(file_size < req_offset) write(0x00);
131
}
132
}
133
134
file_offset = req_offset;
135
}
136
137
int offset() const {
138
if(!fp) return -1; //file not open
139
return file_offset;
140
}
141
142
int size() const {
143
if(!fp) return -1; //file not open
144
return file_size;
145
}
146
147
bool truncate(unsigned size) {
148
if(!fp) return false; //file not open
149
#if !defined(_WIN32)
150
return ftruncate(fileno(fp), size) == 0;
151
#else
152
return _chsize(fileno(fp), size) == 0;
153
#endif
154
}
155
156
bool end() {
157
if(!fp) return true; //file not open
158
return file_offset >= file_size;
159
}
160
161
static bool exists(const string &filename) {
162
#if !defined(_WIN32)
163
struct stat64 data;
164
return stat64(filename, &data) == 0;
165
#else
166
struct __stat64 data;
167
return _wstat64(utf16_t(filename), &data) == 0;
168
#endif
169
}
170
171
static uintmax_t size(const string &filename) {
172
#if !defined(_WIN32)
173
struct stat64 data;
174
stat64(filename, &data);
175
#else
176
struct __stat64 data;
177
_wstat64(utf16_t(filename), &data);
178
#endif
179
180
//not readily possible in msvc; not needed in bizhawk
181
#ifdef BIZHAWK
182
return data.st_size;
183
#else
184
return S_ISREG(data.st_mode) ? data.st_size : 0u; //TEST
185
#endif
186
}
187
188
static time_t timestamp(const string &filename, file::time mode = file::time::create) {
189
#if !defined(_WIN32)
190
struct stat64 data;
191
stat64(filename, &data);
192
#else
193
struct __stat64 data;
194
_wstat64(utf16_t(filename), &data);
195
#endif
196
switch(mode) { default:
197
case file::time::create: return data.st_ctime;
198
case file::time::modify: return data.st_mtime;
199
case file::time::access: return data.st_atime;
200
}
201
}
202
203
bool open() const {
204
return fp;
205
}
206
207
bool open(const string &filename, mode mode_) {
208
if(fp) return false;
209
210
switch(file_mode = mode_) {
211
#if !defined(_WIN32)
212
case mode::read: fp = fopen(filename, "rb" ); break;
213
case mode::write: fp = fopen(filename, "wb+"); break; //need read permission for buffering
214
case mode::readwrite: fp = fopen(filename, "rb+"); break;
215
case mode::writeread: fp = fopen(filename, "wb+"); break;
216
#else
217
case mode::read: fp = _wfopen(utf16_t(filename), L"rb" ); break;
218
case mode::write: fp = _wfopen(utf16_t(filename), L"wb+"); break;
219
case mode::readwrite: fp = _wfopen(utf16_t(filename), L"rb+"); break;
220
case mode::writeread: fp = _wfopen(utf16_t(filename), L"wb+"); break;
221
#endif
222
}
223
if(!fp) return false;
224
buffer_offset = -1; //invalidate buffer
225
file_offset = 0;
226
fseek(fp, 0, SEEK_END);
227
file_size = ftell(fp);
228
fseek(fp, 0, SEEK_SET);
229
return true;
230
}
231
232
void close() {
233
if(!fp) return;
234
buffer_flush();
235
fclose(fp);
236
fp = 0;
237
}
238
239
file() {
240
memset(buffer, 0, sizeof buffer);
241
buffer_offset = -1;
242
buffer_dirty = false;
243
fp = 0;
244
file_offset = 0;
245
file_size = 0;
246
file_mode = mode::read;
247
}
248
249
~file() {
250
close();
251
}
252
253
file& operator=(const file&) = delete;
254
file(const file&) = delete;
255
256
private:
257
enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 };
258
char buffer[buffer_size];
259
int buffer_offset;
260
bool buffer_dirty;
261
FILE *fp;
262
unsigned file_offset;
263
unsigned file_size;
264
mode file_mode;
265
266
void buffer_sync() {
267
if(!fp) return; //file not open
268
if(buffer_offset != (file_offset & ~buffer_mask)) {
269
buffer_flush();
270
buffer_offset = file_offset & ~buffer_mask;
271
fseek(fp, buffer_offset, SEEK_SET);
272
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
273
if(length) unsigned unused = fread(buffer, 1, length, fp);
274
}
275
}
276
277
void buffer_flush() {
278
if(!fp) return; //file not open
279
if(file_mode == mode::read) return; //buffer cannot be written to
280
if(buffer_offset < 0) return; //buffer unused
281
if(buffer_dirty == false) return; //buffer unmodified since read
282
fseek(fp, buffer_offset, SEEK_SET);
283
unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask);
284
if(length) unsigned unused = fwrite(buffer, 1, length, fp);
285
buffer_offset = -1; //invalidate buffer
286
buffer_dirty = false;
287
}
288
};
289
}
290
291
#endif
292
293