#ifndef __MDFN_STREAM_H1#define __MDFN_STREAM_H23// TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument.45#include "emuware/emuware.h"67#include <errno.h>89#include <stdio.h> // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT.10#include <string.h>1112#include <string>1314class Stream15{16public:1718Stream();19virtual ~Stream();2021enum22{23ATTRIBUTE_READABLE = 1U << 0,24ATTRIBUTE_WRITEABLE = 1U << 1,25ATTRIBUTE_SEEKABLE = 1U << 2,26ATTRIBUTE_SLOW_SEEK = 1U << 3,27ATTRIBUTE_SLOW_SIZE = 1U << 428};29virtual uint64 attributes(void) = 0;3031virtual uint8 *map(void) noexcept;32// Map the entirety of the stream data into the address space of the process, if possible, and return a pointer.33// (the returned pointer must be cached, and returned on any subsequent calls to map() without an unmap()34// in-between, to facilitate a sort of "feature-testing", to determine if an alternative like "MemoryStream"35// should be used).36//37// If the mapping fails for whatever reason, return NULL rather than throwing an exception.38//39// For code using this functionality, ensure usage of map_size() instead of size(), unless you're only using a specific derived40// class like MemoryStream() where the value returned by size() won't change unexpectedly due to outside factors.4142virtual uint64 map_size(void) noexcept;43// The size of the memory mapping area, point to which returned by map().44//45// Returns 0 on supported, or if no mapping currently exists.4647virtual void unmap(void) noexcept;48// Unmap the stream data from the address space. (Possibly invalidating the pointer returned from map()).49// (must automatically be called, if necessary, from the destructor).50//51// If the data can't be "unmapped" as such because it was never mmap()'d or similar in the first place(such as with MemoryStream),52// then this will be a nop.5354virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;55virtual void write(const void *data, uint64 count) = 0;5657virtual void truncate(uint64 length) = 0; // Should have ftruncate()-like semantics; but avoid using it to extend files.5859virtual void seek(int64 offset, int whence = SEEK_SET) = 0;60inline void rewind(void)61{62seek(0, SEEK_SET);63}64virtual uint64 tell(void) = 0;65virtual uint64 size(void) = 0; // May implicitly call flush() if the stream is writeable.66virtual void flush(void) = 0;67virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream.68// Necessary since this operation can fail(running out of disk space, for instance),69// and throw an exception in the destructor would be a Bad Idea(TM).70//71// Manually calling this function isn't strictly necessary, but recommended when the72// stream is writeable; it will be called automatically from the destructor, with any73// exceptions thrown caught and logged.7475//76// Utility functions(TODO):77//78INLINE uint8 get_u8(void)79{80uint8 ret;8182read(&ret, sizeof(ret));8384return ret;85}8687INLINE void put_u8(uint8 c)88{89write(&c, sizeof(c));90}919293template<typename T>94INLINE T get_NE(void)95{96T ret;9798read(&ret, sizeof(ret));99100return ret;101}102103104template<typename T>105INLINE T get_RE(void)106{107uint8 tmp[sizeof(T)];108union109{110T ret;111uint8 ret_u8[sizeof(T)];112};113114read(tmp, sizeof(tmp));115116for(unsigned i = 0; i < sizeof(T); i++)117ret_u8[i] = tmp[sizeof(T) - 1 - i];118119return ret;120}121122template<typename T>123INLINE void put_NE(T c)124{125write(&c, sizeof(c));126}127128template<typename T>129INLINE void put_RE(T c)130{131uint8 tmp[sizeof(T)];132133for(unsigned i = 0; i < sizeof(T); i++)134tmp[i] = ((uint8 *)&c)[sizeof(T) - 1 - i];135136write(tmp, sizeof(tmp));137}138139template<typename T>140INLINE T get_LE(void)141{142#ifdef LSB_FIRST143return get_NE<T>();144#else145return get_RE<T>();146#endif147}148149template<typename T>150INLINE void put_LE(T c)151{152#ifdef LSB_FIRST153return put_NE<T>(c);154#else155return put_RE<T>(c);156#endif157}158159template<typename T>160INLINE T get_BE(void)161{162#ifndef LSB_FIRST163return get_NE<T>();164#else165return get_RE<T>();166#endif167}168169template<typename T>170INLINE void put_BE(T c)171{172#ifndef LSB_FIRST173return put_NE<T>(c);174#else175return put_RE<T>(c);176#endif177}178179INLINE void put_string(const char* str)180{181write(str, strlen(str));182}183184// Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or 256 on EOF and185// data has been read into "str", and -1 on EOF when no data has been read into "str".186// The line-end char won't be added to "str".187// It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n).188// ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part189// of it would be up to the STL implementation).190// Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream)191virtual int get_line(std::string &str);192193virtual void put_line(const std::string& str);194195virtual void print_format(const char *format, ...) MDFN_FORMATSTR(gnu_printf, 2, 3);196197#if 0198int scanf(const char *format, ...) MDFN_FORMATSTR(gnu_scanf, 2, 3);199void put_string(const char *str);200void put_string(const std::string &str);201#endif202203//204// Read until end-of-stream(or count), discarding any read data, and returns the amount of data "read".205// (Useful for detecting and printing warnings about extra garbage data without needing to call size(),206// which can be problematic for some types of Streams).207uint64 read_discard(uint64 count = ~(uint64)0);208209//210// Reads stream starting at the current stream position(as returned by tell()), into memory allocated with malloc() and realloc(), and211// sets *data_out to a pointer to the memory(which the caller will need to free() at some point).212//213// *data_out is only an output.214//215// If size_limit is/will be exceeded, an exception will be thrown, and *data_out will not be written to.216//217// Will return the amount of data read(and the size of the alloced memory).218//219uint64 alloc_and_read(void** data_out, uint64 size_limit = ~(uint64)0);220};221222#endif223224225