1 #ifndef __MDFN_STREAM_H 2 #define __MDFN_STREAM_H 3 4 // TODO/WIP 5 6 // TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument. 7 8 #include "mednafen.h" 9 #include <errno.h> 10 11 #include <stdio.h> // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT. 12 13 #define MODE_READ 0 14 #define MODE_WRITE 1 15 #define MODE_WRITE_SAFE 2 16 #define MODE_WRITE_INPLACE 3 17 18 class Stream 19 { 20 public: 21 22 Stream(); 23 virtual ~Stream(); 24 25 virtual uint64_t read(void *data, uint64_t count, bool error_on_eos = true) = 0; 26 virtual void write(const void *data, uint64_t count) = 0; 27 28 virtual void truncate(uint64 length) = 0; /* Should have ftruncate()-like semantics; but avoid using it to extend files. */ 29 virtual void flush(void) = 0; 30 31 virtual void seek(int64_t offset, int whence) = 0; 32 virtual uint64_t tell(void) = 0; 33 virtual uint64_t size(void) = 0; 34 virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream. 35 // Necessary since this operation can fail(running out of disk space, for instance), 36 // and throw an exception in the destructor would be a Bad Idea(TM). 37 // 38 // Manually calling this function isn't strictly necessary, but recommended when the 39 // stream is writeable; it will be called automatically from the destructor, with any 40 // exceptions thrown caught and logged. 41 42 // 43 // Utility functions(TODO): 44 // get_u8(void)45 INLINE uint8_t get_u8(void) 46 { 47 uint8_t ret; 48 49 read(&ret, sizeof(ret)); 50 51 return ret; 52 } 53 put_u8(uint8_t c)54 INLINE void put_u8(uint8_t c) 55 { 56 write(&c, sizeof(c)); 57 } 58 59 60 template<typename T> get_NE(void)61 INLINE T get_NE(void) 62 { 63 T ret; 64 65 read(&ret, sizeof(ret)); 66 67 return ret; 68 } 69 70 template<typename T> put_NE(T c)71 INLINE void put_NE(T c) 72 { 73 write(&c, sizeof(c)); 74 } 75 76 77 template<typename T> get_RE(void)78 INLINE T get_RE(void) 79 { 80 uint8_t tmp[sizeof(T)]; 81 T ret = 0; 82 83 read(tmp, sizeof(tmp)); 84 85 for(unsigned i = 0; i < sizeof(T); i++) 86 ret |= (T)tmp[i] << (i * 8); 87 88 return ret; 89 } 90 91 template<typename T> put_RE(T c)92 INLINE void put_RE(T c) 93 { 94 uint8_t tmp[sizeof(T)]; 95 96 for(unsigned i = 0; i < sizeof(T); i++) 97 tmp[i] = ((uint8_t *)&c)[sizeof(T) - 1 - i]; 98 99 write(tmp, sizeof(tmp)); 100 } 101 102 template<typename T> get_LE(void)103 INLINE T get_LE(void) 104 { 105 #ifdef MSB_FIRST 106 return get_RE<T>(); 107 #else 108 return get_NE<T>(); 109 #endif 110 } 111 112 template<typename T> put_LE(T c)113 INLINE void put_LE(T c) 114 { 115 #ifdef MSB_FIRST 116 return put_RE<T>(c); 117 #else 118 return put_NE<T>(c); 119 #endif 120 } 121 122 template<typename T> get_BE(void)123 INLINE T get_BE(void) 124 { 125 #ifdef MSB_FIRST 126 return get_NE<T>(); 127 #else 128 return get_RE<T>(); 129 #endif 130 } 131 132 template<typename T> put_BE(T c)133 INLINE void put_BE(T c) 134 { 135 #ifdef MSB_FIRST 136 return put_NE<T>(c); 137 #else 138 return put_RE<T>(c); 139 #endif 140 } 141 142 // Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or -1 on EOF. 143 // The line-end char won't be added to "str". 144 // It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n). 145 // ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part 146 // of it would be up to the STL implementation). 147 // Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream) 148 virtual int get_line(std::string &str); 149 }; 150 #endif 151