1 #ifndef NALL_FILE_HPP 2 #define NALL_FILE_HPP 3 4 #include <stdio.h> 5 #include <string.h> 6 7 #if !defined(_WIN32) 8 #include <unistd.h> 9 #else 10 #include <io.h> 11 #endif 12 13 #include <nall/stdint.hpp> 14 #include <nall/utf8.hpp> 15 #include <nall/utility.hpp> 16 17 namespace nall { fopen_utf8(const char * utf8_filename,const char * mode)18 inline FILE* fopen_utf8(const char *utf8_filename, const char *mode) { 19 #if !defined(_WIN32) 20 return fopen(utf8_filename, mode); 21 #else 22 return _wfopen(utf16_t(utf8_filename), utf16_t(mode)); 23 #endif 24 } 25 26 class file : noncopyable { 27 public: 28 enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread }; 29 enum SeekMode { seek_absolute, seek_relative }; 30 read()31 uint8_t read() { 32 if(!fp) return 0xff; //file not open 33 if(file_mode == mode_write) return 0xff; //reads not permitted 34 if(file_offset >= file_size) return 0xff; //cannot read past end of file 35 buffer_sync(); 36 return buffer[(file_offset++) & buffer_mask]; 37 } 38 readl(unsigned length=1)39 uintmax_t readl(unsigned length = 1) { 40 uintmax_t data = 0; 41 for(int i = 0; i < length; i++) { 42 data |= (uintmax_t)read() << (i << 3); 43 } 44 return data; 45 } 46 readm(unsigned length=1)47 uintmax_t readm(unsigned length = 1) { 48 uintmax_t data = 0; 49 while(length--) { 50 data <<= 8; 51 data |= read(); 52 } 53 return data; 54 } 55 read(uint8_t * buffer,unsigned length)56 void read(uint8_t *buffer, unsigned length) { 57 while(length--) *buffer++ = read(); 58 } 59 write(uint8_t data)60 void write(uint8_t data) { 61 if(!fp) return; //file not open 62 if(file_mode == mode_read) return; //writes not permitted 63 buffer_sync(); 64 buffer[(file_offset++) & buffer_mask] = data; 65 buffer_dirty = true; 66 if(file_offset > file_size) file_size = file_offset; 67 } 68 writel(uintmax_t data,unsigned length=1)69 void writel(uintmax_t data, unsigned length = 1) { 70 while(length--) { 71 write(data); 72 data >>= 8; 73 } 74 } 75 writem(uintmax_t data,unsigned length=1)76 void writem(uintmax_t data, unsigned length = 1) { 77 for(int i = length - 1; i >= 0; i--) { 78 write(data >> (i << 3)); 79 } 80 } 81 write(const uint8_t * buffer,unsigned length)82 void write(const uint8_t *buffer, unsigned length) { 83 while(length--) write(*buffer++); 84 } 85 print(const char * string)86 void print(const char *string) { 87 if(!string) return; 88 while(*string) write(*string++); 89 } 90 flush()91 void flush() { 92 buffer_flush(); 93 fflush(fp); 94 } 95 seek(int offset,SeekMode mode=seek_absolute)96 void seek(int offset, SeekMode mode = seek_absolute) { 97 if(!fp) return; //file not open 98 buffer_flush(); 99 100 intmax_t req_offset = file_offset; 101 switch(mode) { 102 case seek_absolute: req_offset = offset; break; 103 case seek_relative: req_offset += offset; break; 104 } 105 106 if(req_offset < 0) req_offset = 0; //cannot seek before start of file 107 if(req_offset > file_size) { 108 if(file_mode == mode_read) { //cannot seek past end of file 109 req_offset = file_size; 110 } else { //pad file to requested location 111 file_offset = file_size; 112 while(file_size < req_offset) write(0x00); 113 } 114 } 115 116 file_offset = req_offset; 117 } 118 offset()119 int offset() { 120 if(!fp) return -1; //file not open 121 return file_offset; 122 } 123 size()124 int size() { 125 if(!fp) return -1; //file not open 126 return file_size; 127 } 128 truncate(unsigned size)129 bool truncate(unsigned size) { 130 if(!fp) return false; //file not open 131 #if !defined(_WIN32) 132 return ftruncate(fileno(fp), size) == 0; 133 #else 134 return _chsize(fileno(fp), size) == 0; 135 #endif 136 } 137 end()138 bool end() { 139 if(!fp) return true; //file not open 140 return file_offset >= file_size; 141 } 142 exists(const char * fn)143 static bool exists(const char *fn) { 144 #if !defined(_WIN32) 145 FILE *fp = fopen(fn, "rb"); 146 #else 147 FILE *fp = _wfopen(utf16_t(fn), L"rb"); 148 #endif 149 if(fp) { 150 fclose(fp); 151 return true; 152 } 153 return false; 154 } 155 size(const char * fn)156 static unsigned size(const char *fn) { 157 #if !defined(_WIN32) 158 FILE *fp = fopen(fn, "rb"); 159 #else 160 FILE *fp = _wfopen(utf16_t(fn), L"rb"); 161 #endif 162 unsigned filesize = 0; 163 if(fp) { 164 fseek(fp, 0, SEEK_END); 165 filesize = ftell(fp); 166 fclose(fp); 167 } 168 return filesize; 169 } 170 open()171 bool open() { 172 return fp; 173 } 174 open(const char * fn,FileMode mode)175 bool open(const char *fn, FileMode mode) { 176 if(fp) return false; 177 178 switch(file_mode = mode) { 179 #if !defined(_WIN32) 180 case mode_read: fp = fopen(fn, "rb"); break; 181 case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering 182 case mode_readwrite: fp = fopen(fn, "rb+"); break; 183 case mode_writeread: fp = fopen(fn, "wb+"); break; 184 #else 185 case mode_read: fp = _wfopen(utf16_t(fn), L"rb"); break; 186 case mode_write: fp = _wfopen(utf16_t(fn), L"wb+"); break; 187 case mode_readwrite: fp = _wfopen(utf16_t(fn), L"rb+"); break; 188 case mode_writeread: fp = _wfopen(utf16_t(fn), L"wb+"); break; 189 #endif 190 } 191 if(!fp) return false; 192 buffer_offset = -1; //invalidate buffer 193 file_offset = 0; 194 fseek(fp, 0, SEEK_END); 195 file_size = ftell(fp); 196 fseek(fp, 0, SEEK_SET); 197 return true; 198 } 199 close()200 void close() { 201 if(!fp) return; 202 buffer_flush(); 203 fclose(fp); 204 fp = 0; 205 } 206 file()207 file() { 208 memset(buffer, 0, sizeof buffer); 209 buffer_offset = -1; 210 buffer_dirty = false; 211 fp = 0; 212 file_offset = 0; 213 file_size = 0; 214 file_mode = mode_read; 215 } 216 ~file()217 ~file() { 218 close(); 219 } 220 221 private: 222 enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 }; 223 char buffer[buffer_size]; 224 int buffer_offset; 225 bool buffer_dirty; 226 FILE *fp; 227 unsigned file_offset; 228 unsigned file_size; 229 FileMode file_mode; 230 buffer_sync()231 void buffer_sync() { 232 if(!fp) return; //file not open 233 if(buffer_offset != (file_offset & ~buffer_mask)) { 234 buffer_flush(); 235 buffer_offset = file_offset & ~buffer_mask; 236 fseek(fp, buffer_offset, SEEK_SET); 237 unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); 238 if(length) unsigned unused = fread(buffer, 1, length, fp); 239 } 240 } 241 buffer_flush()242 void buffer_flush() { 243 if(!fp) return; //file not open 244 if(file_mode == mode_read) return; //buffer cannot be written to 245 if(buffer_offset < 0) return; //buffer unused 246 if(buffer_dirty == false) return; //buffer unmodified since read 247 fseek(fp, buffer_offset, SEEK_SET); 248 unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); 249 if(length) unsigned unused = fwrite(buffer, 1, length, fp); 250 buffer_offset = -1; //invalidate buffer 251 buffer_dirty = false; 252 } 253 }; 254 } 255 256 #endif 257