#ifndef __MDFN_STREAM_H1#define __MDFN_STREAM_H23// TODO/WIP45// TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument.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>1112#include "octoshock.h"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) = 0; // Map the entirety of the stream data into the address space of the process, if possible, and return a pointer.32// (the returned pointer must be cached, and returned on any subsequent calls to map() without an unmap()33// in-between, to facilitate a sort of "feature-testing", to determine if an alternative like "MemoryStream"34// should be used).35//36// If the mapping fails for whatever reason, return NULL rather than throwing an exception.37//3839virtual void unmap(void) = 0; // Unmap the stream data from the address space. (Possibly invalidating the pointer returned from map()).40// (must automatically be called, if necessary, from the destructor).41//42// 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),43// then this will be a nop.4445virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;46virtual void write(const void *data, uint64 count) = 0;4748virtual void seek(int64 offset, int whence = SEEK_SET) = 0;49inline void rewind(void)50{51seek(0, SEEK_SET);52}53virtual int64 tell(void) = 0;54virtual int64 size(void) = 0;55virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream.56// Necessary since this operation can fail(running out of disk space, for instance),57// and throw an exception in the destructor would be a Bad Idea(TM).58//59// Manually calling this function isn't strictly necessary, but recommended when the60// stream is writeable; it will be called automatically from the destructor, with any61// exceptions thrown caught and logged.6263//64// Utility functions(TODO):65//66INLINE uint8 get_u8(void)67{68uint8 ret;6970read(&ret, sizeof(ret));7172return ret;73}7475INLINE void put_u8(uint8 c)76{77write(&c, sizeof(c));78}798081template<typename T>82INLINE T get_NE(void)83{84T ret;8586read(&ret, sizeof(ret));8788return ret;89}9091template<typename T>92INLINE void put_NE(T c)93{94write(&c, sizeof(c));95}969798template<typename T>99INLINE T get_RE(void)100{101uint8 tmp[sizeof(T)];102T ret = 0;103104read(tmp, sizeof(tmp));105106for(unsigned i = 0; i < sizeof(T); i++)107ret |= (T)tmp[i] << (i * 8);108109return ret;110}111112template<typename T>113INLINE void put_RE(T c)114{115uint8 tmp[sizeof(T)];116117for(unsigned i = 0; i < sizeof(T); i++)118tmp[i] = ((uint8 *)&c)[sizeof(T) - 1 - i];119120write(tmp, sizeof(tmp));121}122123template<typename T>124INLINE T get_LE(void)125{126#ifdef LSB_FIRST127return get_NE<T>();128#else129return get_RE<T>();130#endif131}132133template<typename T>134INLINE void put_LE(T c)135{136#ifdef LSB_FIRST137return put_NE<T>(c);138#else139return put_RE<T>(c);140#endif141}142143template<typename T>144INLINE T get_BE(void)145{146#ifndef LSB_FIRST147return get_NE<T>();148#else149return get_RE<T>();150#endif151}152153template<typename T>154INLINE void put_BE(T c)155{156#ifndef LSB_FIRST157return put_NE<T>(c);158#else159return put_RE<T>(c);160#endif161}162163// Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or 256 on EOF and164// data has been read into "str", and -1 on EOF when no data has been read into "str".165// The line-end char won't be added to "str".166// It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n).167// ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part168// of it would be up to the STL implementation).169// Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream)170virtual int get_line(std::string &str);171172virtual void put_line(const std::string& str);173174virtual void print_format(const char *format, ...);175176#if 0177int scanf(const char *format, ...) MDFN_FORMATSTR(gnu_scanf, 2, 3);178void put_string(const char *str);179void put_string(const std::string &str);180#endif181};182183// StreamFilter takes ownership of the Stream pointer passed, and will delete it in its destructor.184class StreamFilter : public Stream185{186public:187188StreamFilter();189StreamFilter(Stream *target_arg);190virtual ~StreamFilter();191192virtual uint64 read(void *data, uint64 count, bool error_on_eos = true) = 0;193virtual void write(const void *data, uint64 count) = 0;194virtual void seek(int64 offset, int whence) = 0;195virtual int64 tell(void) = 0;196virtual int64 size(void) = 0;197virtual void close(void) = 0;198199virtual Stream *steal(void);200201private:202Stream *target_stream;203};204205#endif206207208