1#ifndef File_h 2#define File_h 3 4#ifndef Global_h 5#include "Global.h" 6#endif 7 8#include <unistd.h> 9#include <fcntl.h> 10#include <sys/stat.h> 11 12#ifndef _LARGEFILE64_SOURCE 13#define lseek64 ::lseek 14#define open64 ::open 15#endif 16 17 18//================================================================================================= 19// A buffered file abstraction with only 'putChar()' and 'getChar()'. 20 21 22#define File_BufSize 1024 // A small buffer seem to work just as fine as a big one (at least under Linux) 23 24enum FileMode { READ, WRITE }; 25 26class Exception_EOF {}; 27 28 29// WARNING! This code is not thoroughly tested. May contain bugs! 30 31class File { 32 int fd; // Underlying file descriptor. 33 FileMode mode; // Reading or writing. 34 uchar* buf; // Read or write buffer. 35 int size; // Size of buffer (at end of file, less than 'File_BufSize'). 36 int pos; // Current position in buffer 37 bool own_fd; // Do we own the file descriptor? If so, will close file in destructor. 38 39public: 40 #define DEFAULTS fd(-1), mode(READ), buf(NULL), size(-1), pos(0), own_fd(true) 41 File(void) : DEFAULTS {} 42 43 File(int fd, FileMode mode, bool own_fd = true) : DEFAULTS { 44 open(fd, mode, own_fd); } 45 46 File(cchar* name, cchar* mode) : DEFAULTS { 47 open(name, mode); } 48 #undef DEFAULTS 49 50 ~File(void) { 51 close(); } 52 53 // Low-level open. If 'own_fd' is FALSE, descriptor will not be closed by destructor. 54 void open(int fd, FileMode mode, bool own_fd = true); 55 void open(cchar* name, cchar* mode); // FILE* compatible interface. 56 void close(void); 57 58 bool null(void) { // TRUE if no file is opened. 59 return fd == -1; } 60 61 // Don't run UNIX function 'close()' on descriptor in 'File's 'close()'. 62 int releaseDescriptor(void) { 63 if (mode == READ) 64 lseek64(fd, pos - size, SEEK_CUR); 65 own_fd = false; 66 return fd; } 67 68 FileMode getMode(void) { 69 return mode; } 70 71 void setMode(FileMode m) { 72 if (m == mode) return; 73 if (m == READ){ 74 flush(); 75 size = read(fd, buf, File_BufSize); 76 }else{ 77 lseek64(fd, pos - size, SEEK_CUR); 78 size = -1; } 79 mode = m; 80 pos = 0; } 81 82 int getCharQ(void) { // Quick version with minimal overhead : don't call this in wrong mode! 83 #ifdef PARANOID 84 assert(mode == READ); 85 #endif 86 if (pos < size) return (uchar)buf[pos++]; 87 if (size < File_BufSize) return EOF; 88 size = read(fd, buf, File_BufSize); 89 pos = 0; 90 if (size == 0) return EOF; 91 return (uchar)buf[pos++]; } 92 93 int putCharQ(int chr) { // Quick version with minimal overhead : don't call this in wrong mode! 94 #ifdef PARANOID 95 assert(mode == WRITE); 96 #endif 97 if (pos == File_BufSize) 98 write(fd, buf, File_BufSize), 99 pos = 0; 100 return buf[pos++] = (uchar)chr; } 101 102 int getChar(void) { 103 if (mode == WRITE) setMode(READ); 104 return getCharQ(); } 105 106 int putChar(int chr) { 107 if (mode == READ) setMode(WRITE); 108 return putCharQ(chr); } 109 110 bool eof(void) { 111 assert(mode == READ); 112 if (pos < size) return false; 113 if (size < File_BufSize) return true; 114 size = read(fd, buf, File_BufSize); 115 pos = 0; 116 if (size == 0) return true; 117 return false; } 118 119 void flush(void) { 120 assert(mode == WRITE); 121 write(fd, buf, pos); 122 pos = 0; } 123 124 void seek(int64 pos, int whence = SEEK_SET); 125 int64 tell(void); 126}; 127 128 129//================================================================================================= 130// Some nice helper functions: 131 132 133void putUInt (File& out, uint64 val); 134uint64 getUInt (File& in) throw(Exception_EOF); 135static inline uint64 encode64(int64 val) { return (val >= 0) ? (uint64)val << 1 : (((uint64)(~val) << 1) | 1); } 136static inline int64 decode64(uint64 val) { return ((val & 1) == 0) ? (int64)(val >> 1) : ~(int64)(val >> 1); } 137static inline void putInt (File& out, int64 val) { putUInt(out, encode64(val)); } 138static inline uint64 getInt (File& in) { return decode64(getUInt(in)); } 139 140 141//================================================================================================= 142#endif 143