// Lightweight interface for reading data from byte stream // File_Extractor 1.0.0 #ifndef DATA_READER_H #define DATA_READER_H #include "blargg_common.h" /* Some functions accept a long instead of int for convenience where caller has a long due to some other interface, and would otherwise have to get a warning, or cast it (and verify that it wasn't outside the range of an int). To really support huge (>2GB) files, long isn't a solution, since there's no guarantee it's more than 32 bits. We'd need to use long long (if available), or something compiler-specific, and change all places file sizes or offsets are used. */ // Supports reading and finding out how many bytes are remaining class Data_Reader { public: // Reads min(*n,remain()) bytes and sets *n to this number, thus trying to read more // tham remain() bytes doesn't result in error, just *n being set to remain(). blargg_err_t read_avail( void* p, int* n ); blargg_err_t read_avail( void* p, long* n ); // Reads exactly n bytes, or returns error if they couldn't ALL be read. // Reading past end of file results in blargg_err_file_eof. blargg_err_t read( void* p, int n ); // Number of bytes remaining until end of file BOOST::uint64_t remain() const { return remain_; } // Reads and discards n bytes. Skipping past end of file results in blargg_err_file_eof. blargg_err_t skip( int n ); virtual ~Data_Reader() { } private: // noncopyable Data_Reader( const Data_Reader& ); Data_Reader& operator = ( const Data_Reader& ); // Derived interface protected: Data_Reader() : remain_( 0 ) { } // Sets remain void set_remain( BOOST::uint64_t n ) { assert( n >= 0 ); remain_ = n; } // Do same as read(). Guaranteed that 0 < n <= remain(). Value of remain() is updated // AFTER this call succeeds, not before. set_remain() should NOT be called from this. virtual blargg_err_t read_v( void*, int n ) BLARGG_PURE( { (void)n; return blargg_ok; } ) // Do same as skip(). Guaranteed that 0 < n <= remain(). Default just reads data // and discards it. Value of remain() is updated AFTER this call succeeds, not // before. set_remain() should NOT be called from this. virtual blargg_err_t skip_v( int n ); // Implementation public: BLARGG_DISABLE_NOTHROW private: BOOST::uint64_t remain_; }; // Supports seeking in addition to Data_Reader operations class File_Reader : public Data_Reader { public: // Size of file BOOST::uint64_t size() const { return size_; } // Current position in file BOOST::uint64_t tell() const { return size_ - remain(); } // Goes to new position blargg_err_t seek( BOOST::uint64_t ); // Derived interface protected: // Sets size and resets position void set_size( BOOST::uint64_t n ) { size_ = n; Data_Reader::set_remain( n ); } void set_size( int n ) { set_size( STATIC_CAST(BOOST::uint64_t, n) ); } void set_size( long n ) { set_size( STATIC_CAST(BOOST::uint64_t, n) ); } // Sets reported position void set_tell( BOOST::uint64_t i ) { assert( 0 <= i && i <= size_ ); Data_Reader::set_remain( size_ - i ); } // Do same as seek(). Guaranteed that 0 <= n <= size(). Value of tell() is updated // AFTER this call succeeds, not before. set_* functions should NOT be called from this. virtual blargg_err_t seek_v( BOOST::uint64_t n ) BLARGG_PURE( { (void)n; return blargg_ok; } ) // Implementation protected: File_Reader() : size_( 0 ) { } virtual blargg_err_t skip_v( BOOST::uint64_t ); private: BOOST::uint64_t size_; void set_remain(); // avoid accidental use of set_remain }; // Reads from file on disk class Std_File_Reader : public File_Reader { public: // Opens file blargg_err_t open( const char path [] ); // Closes file if one was open void close(); // Switches to unbuffered mode. Useful if buffering is already being // done at a higher level. void make_unbuffered(); // Implementation public: Std_File_Reader(); virtual ~Std_File_Reader(); protected: virtual blargg_err_t read_v( void*, int ); virtual blargg_err_t seek_v( BOOST::uint64_t ); private: void* file_; }; // Treats range of memory as a file class Mem_File_Reader : public File_Reader { public: Mem_File_Reader( const void* begin, long size ); // Implementation protected: virtual blargg_err_t read_v( void*, int ); virtual blargg_err_t seek_v( int ); private: const char* const begin; }; // Allows only count bytes to be read from reader passed class Subset_Reader : public Data_Reader { public: Subset_Reader( Data_Reader*, BOOST::uint64_t count ); // Implementation protected: virtual blargg_err_t read_v( void*, int ); private: Data_Reader* const in; }; // Joins already-read header and remaining data into original file. // Meant for cases where you've already read header and don't want // to seek and re-read data (for efficiency). class Remaining_Reader : public Data_Reader { public: Remaining_Reader( void const* header, int header_size, Data_Reader* ); // Implementation protected: virtual blargg_err_t read_v( void*, int ); private: Data_Reader* const in; void const* header; int header_remain; }; // Invokes callback function to read data extern "C" { // necessary to be usable from C typedef const char* (*callback_reader_func_t)( void* user_data, // Same value passed to constructor void* out, // Buffer to place data into int count // Number of bytes to read ); } class Callback_Reader : public Data_Reader { public: typedef callback_reader_func_t callback_t; Callback_Reader( callback_t, BOOST::uint64_t size, void* user_data ); // Implementation protected: virtual blargg_err_t read_v( void*, int ); private: callback_t const callback; void* const user_data; }; // Invokes callback function to read data extern "C" { // necessary to be usable from C typedef const char* (*callback_file_reader_func_t)( void* user_data, // Same value passed to constructor void* out, // Buffer to place data into int count, // Number of bytes to read BOOST::uint64_t pos // Position in file to read from ); } class Callback_File_Reader : public File_Reader { public: typedef callback_file_reader_func_t callback_t; Callback_File_Reader( callback_t, BOOST::uint64_t size, void* user_data ); // Implementation protected: virtual blargg_err_t read_v( void*, int ); virtual blargg_err_t seek_v( int ); private: callback_t const callback; void* const user_data; }; #ifdef HAVE_ZLIB_H // Reads file compressed with gzip (or uncompressed) class Gzip_File_Reader : public File_Reader { public: // Opens possibly gzipped file blargg_err_t open( const char path [] ); // Closes file if one was open void close(); // Implementation public: Gzip_File_Reader(); ~Gzip_File_Reader(); protected: virtual blargg_err_t read_v( void*, int ); virtual blargg_err_t seek_v( int ); private: // void* so "zlib.h" doesn't have to be included here void* file_; }; #endif char* blargg_to_utf8( const blargg_wchar_t* ); blargg_wchar_t* blargg_to_wide( const char* ); #endif