diff --git a/include/library/binarystream.hpp b/include/library/binarystream.hpp index d1464a47..991e644d 100644 --- a/include/library/binarystream.hpp +++ b/include/library/binarystream.hpp @@ -9,63 +9,250 @@ #include #include -struct binary_output_stream +namespace binarystream +{ +/** + * Output binary stream. + */ +struct output { public: - binary_output_stream(); - binary_output_stream(std::ostream& s); +/** + * Create a new output binary stream outputting to internal buffer. + */ + output(); +/** + * Create a new output binary stream outputting to given output stream. + * + * Parameter s: The stream to output to. + */ + output(std::ostream& s); +/** + * Output a byte to stream (1 byte). + * + * Parameter byte: The byte to output. + */ void byte(uint8_t byte); +/** + * Output a number to stream. + * + * Parameter number: The number to output. + */ void number(uint64_t number); +/** + * Count number of bytes needed to store given number. + * + * Parameter number: The number to query. + * Return: The number of bytes needed. + */ size_t numberbytes(uint64_t number); +/** + * Output a 32-bit number to stream (4 byte). + * + * Parameter number: The number to output. + */ void number32(uint32_t number); +/** + * Output a string with explicit length indication to the stream. + * + * This takes space for one number + number of bytes in the string. + * + * Parameter string: The number to output. + */ void string(const std::string& string); +/** + * Output a string without length indication to the stream. + * + * This takes space for number of bytes in the string. + * + * Parameter string: The number to output. + */ void string_implicit(const std::string& string); +/** + * Output a octet string without length indication to the stream. + * + * This takes space for number of bytes in the sequence. + * + * Parameter blob: The octet string to output. + */ void blob_implicit(const std::vector& blob); +/** + * Output a octet string without length indication to the stream. + * + * This takes space for number of bytes in the sequence. + * + * Parameter buf: The input buffer to read the octet string from. + * Parameter bufsize: The size of buffer in bytes. + */ void raw(const void* buf, size_t bufsize); - void extension(uint32_t tag, std::function fn, bool even_empty = false); - void extension(uint32_t tag, std::function fn, bool even_empty, +/** + * Output a extension substream into stream. + * + * Parameter tag: Tag identifying the extension member type. + * Parameter fn: Function writing the contents of the extension substream. + * Parameter even_empty: If true, the member is written even if empty (otherwise it is elided). + */ + void extension(uint32_t tag, std::function fn, bool even_empty = false); +/** + * Output a extension substream with known size into stream. + * + * In exchange for having to know the size of the payload, this is faster to write as it avoids buffering. + * + * Parameter tag: Tag identifying the extension member type. + * Parameter fn: Function writing the contents of the extension substream. + * Parameter even_empty: If true, the member is written even if empty (otherwise it is elided). + * Parameter size_precognition: The known size of the payload. + */ + void extension(uint32_t tag, std::function fn, bool even_empty, size_t size_precognition); +/** + * Output explicit extension tag. + * + * This has to be followed by writing size bytes, forming the payload. + * + * Parameter tag: The Tag identifying the extension member type. + * Parameter size: Size of the payload. + */ void write_extension_tag(uint32_t tag, uint64_t size); +/** + * Get the output stream contents. + * + * The output stream has to use internal buffer for this to work. + * + * Returns: The internal buffer contents. + */ std::string get(); private: std::ostream& strm; std::ostringstream buf; }; -struct binary_input_stream +/** + * Input binary stream. + */ +struct input { public: +/** + * Extension tag handler. + */ struct binary_tag_handler { +/** + * The extension tag to activate on. + */ uint32_t tag; - std::function fn; +/** + * Handler function for the tag. + * + * Parameter s: The substream of extension. + */ + std::function fn; }; - binary_input_stream(std::istream& s); - binary_input_stream(binary_input_stream& s, uint64_t len); +/** + * Create a new top-level input stream, reading from specified stream. + */ + input(std::istream& s); +/** + * Create a new input substream, under specified top-level stream and with specified length. + * + * Parameter s: The top-level stream. + * Parameter len: Amount of payload in extension stream. + */ + input(input& s, uint64_t len); +/** + * Read a byte. + * + * Returns: The read byte. + */ uint8_t byte(); +/** + * Read a number. + * + * Returns: The read number. + */ uint64_t number(); +/** + * Read a 32-bit number. + * + * Returns: The read number. + */ uint32_t number32(); +/** + * Read a string with explicit length indication. + * + * Returns: The read string. + */ std::string string(); +/** + * Read a string without explicit length indication, quitting when reaching end of extension substream. + * + * Can be only used in extension substreams. + * + * Returns: The read string. + */ std::string string_implicit(); +/** + * Read a octet string without explicit length indication, quitting when reaching end of extension substream. + * + * Can be only used in extension substreams. + * + * Parameter blob: Store the read octet string here. + */ void blob_implicit(std::vector& blob); +/** + * Read a octet string of specified length. + * + * Parameter buf: Buffer to store the octet string to. + * Parameter bufsize: The amount of data to read. + */ void raw(void* buf, size_t bufsize); - void extension(std::function fn); +/** + * Read extension substreams. + * + * This reads substreams until the end of stream. + * + * Parameter fn: Function handling the read extension substream. + * Parameter tag: The type tag of read substream. + * Parameter s: The substream with contents of extension substream. + */ + void extension(std::function fn); +/** + * Read extension substreams. + * + * This reads substreams until the end of stream. + * + * Parameter funcs: Table of functions to call for each known extension type. + * Parameter default_hdlr: Handler for unknown types (parameters as in other ::extension()). + */ void extension(std::initializer_list funcs, - std::function default_hdlr); + std::function default_hdlr); +/** + * Get number of bytes left in substream. + * + * Can only be used for substreams. + * + * Returns: Number of bytes left. + */ uint64_t get_left() { if(!parent) - throw std::logic_error("binary_input_stream::get_left() can only be used in substreams"); + throw std::logic_error("binarystream::input::get_left() can only be used in substreams"); return left; } private: bool read(char* buf, size_t size, bool allow_none = false); void flush(); - binary_input_stream* parent; + input* parent; std::istream& strm; uint64_t left; }; -void binary_null_default(uint32_t tag, binary_input_stream& s); +/** + * Do nothing. Handy as second parameter for two-parameter output::extension() if the table enumerates all non- + * ignored types. + */ +void null_default(uint32_t tag, input& s); +} #endif diff --git a/src/core/moviefile.cpp b/src/core/moviefile.cpp index 753262d1..2c522115 100644 --- a/src/core/moviefile.cpp +++ b/src/core/moviefile.cpp @@ -83,7 +83,7 @@ void write_linefile(zip_writer& w, const std::string& member, const std::string& namespace { - void binary_read_movie(binary_input_stream& in, controller_frame_vector& v) + void binary_read_movie(binarystream::input& in, controller_frame_vector& v) { uint64_t stride = v.get_stride(); uint64_t pageframes = v.get_frames_per_page(); @@ -100,7 +100,7 @@ namespace v.resize(vsize); } - void binary_write_movie(binary_output_stream& out, controller_frame_vector& v) + void binary_write_movie(binarystream::output& out, controller_frame_vector& v) { uint64_t pages = v.get_page_count(); uint64_t stride = v.get_stride(); @@ -519,7 +519,7 @@ moviefile::brief_info::brief_info(const std::string& filename) void moviefile::brief_info::binary_io(std::istream& _stream) { - binary_input_stream in(_stream); + binarystream::input in(_stream); sysregion = in.string(); //Discard the settings. while(in.byte()) { @@ -527,17 +527,17 @@ void moviefile::brief_info::binary_io(std::istream& _stream) in.string(); } in.extension({ - {TAG_CORE_VERSION, [this](binary_input_stream& s) { + {TAG_CORE_VERSION, [this](binarystream::input& s) { this->corename = s.string_implicit(); - }},{TAG_PROJECT_ID, [this](binary_input_stream& s) { + }},{TAG_PROJECT_ID, [this](binarystream::input& s) { this->projectid = s.string_implicit(); - }},{TAG_SAVESTATE, [this](binary_input_stream& s) { + }},{TAG_SAVESTATE, [this](binarystream::input& s) { this->current_frame = s.number(); - }},{TAG_RRDATA, [this](binary_input_stream& s) { + }},{TAG_RRDATA, [this](binarystream::input& s) { std::vector c_rrdata; s.blob_implicit(c_rrdata); this->rerecords = rrdata.count(c_rrdata); - }},{TAG_ROMHASH, [this](binary_input_stream& s) { + }},{TAG_ROMHASH, [this](binarystream::input& s) { uint8_t n = s.byte(); std::string h = s.string_implicit(); if(n > 2 * ROM_SLOT_COUNT) @@ -546,14 +546,14 @@ void moviefile::brief_info::binary_io(std::istream& _stream) this->hashxml[n >> 1] = h; else this->hash[n >> 1] = h; - }},{TAG_ROMHINT, [this](binary_input_stream& s) { + }},{TAG_ROMHINT, [this](binarystream::input& s) { uint8_t n = s.byte(); std::string h = s.string_implicit(); if(n > ROM_SLOT_COUNT) return; this->hint[n] = h; }} - }, binary_null_default); + }, binarystream::null_default); } moviefile::moviefile() throw(std::bad_alloc) @@ -799,49 +799,49 @@ Following need to be saved: */ void moviefile::binary_io(std::ostream& _stream) throw(std::bad_alloc, std::runtime_error) { - binary_output_stream out(_stream); + binarystream::output out(_stream); out.string(gametype->get_name()); - write_settings(out, settings, gametype->get_type().get_settings(), - [](binary_output_stream& s, const std::string& name, const std::string& value) -> void { + write_settings(out, settings, gametype->get_type().get_settings(), + [](binarystream::output& s, const std::string& name, const std::string& value) -> void { s.byte(0x01); s.string(name); s.string(value); }); out.byte(0x00); - out.extension(TAG_MOVIE_TIME, [this](binary_output_stream& s) { + out.extension(TAG_MOVIE_TIME, [this](binarystream::output& s) { s.number(this->movie_rtc_second); s.number(this->movie_rtc_subsecond); }); - out.extension(TAG_PROJECT_ID, [this](binary_output_stream& s) { + out.extension(TAG_PROJECT_ID, [this](binarystream::output& s) { s.string_implicit(this->projectid); }); - out.extension(TAG_CORE_VERSION, [this](binary_output_stream& s) { + out.extension(TAG_CORE_VERSION, [this](binarystream::output& s) { this->coreversion = this->gametype->get_type().get_core_identifier(); s.string_implicit(this->coreversion); }); for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) { - out.extension(TAG_ROMHASH, [this, i](binary_output_stream& s) { + out.extension(TAG_ROMHASH, [this, i](binarystream::output& s) { if(!this->romimg_sha256[i].length()) return; s.byte(2 * i); s.string_implicit(this->romimg_sha256[i]); }); - out.extension(TAG_ROMHASH, [this, i](binary_output_stream& s) { + out.extension(TAG_ROMHASH, [this, i](binarystream::output& s) { if(!this->romxml_sha256[i].length()) return; s.byte(2 * i + 1); s.string_implicit(this->romxml_sha256[i]); }); - out.extension(TAG_ROMHINT, [this, i](binary_output_stream& s) { + out.extension(TAG_ROMHINT, [this, i](binarystream::output& s) { if(!this->namehint[i].length()) return; s.byte(i); s.string_implicit(this->namehint[i]); }); } - out.extension(TAG_RRDATA, [this](binary_output_stream& s) { + out.extension(TAG_RRDATA, [this](binarystream::output& s) { uint64_t count; std::vector rrd; count = rrdata.write(rrd); @@ -849,16 +849,16 @@ void moviefile::binary_io(std::ostream& _stream) throw(std::bad_alloc, std::runt }); for(auto i : movie_sram) - out.extension(TAG_MOVIE_SRAM, [&i](binary_output_stream& s) { + out.extension(TAG_MOVIE_SRAM, [&i](binarystream::output& s) { s.string(i.first); s.blob_implicit(i.second); }); - out.extension(TAG_ANCHOR_SAVE, [this](binary_output_stream& s) { + out.extension(TAG_ANCHOR_SAVE, [this](binarystream::output& s) { s.blob_implicit(this->anchor_savestate); }); if(is_savestate) { - out.extension(TAG_SAVESTATE, [this](binary_output_stream& s) { + out.extension(TAG_SAVESTATE, [this](binarystream::output& s) { s.number(this->save_frame); s.number(this->lagged_frames); s.number(this->rtc_second); @@ -872,47 +872,47 @@ void moviefile::binary_io(std::ostream& _stream) throw(std::bad_alloc, std::runt out.numberbytes(rtc_subsecond) + out.numberbytes(pollcounters.size()) + 4 * pollcounters.size() + 1 + savestate.size()); - out.extension(TAG_HOSTMEMORY, [this](binary_output_stream& s) { + out.extension(TAG_HOSTMEMORY, [this](binarystream::output& s) { s.blob_implicit(this->host_memory); }); - out.extension(TAG_SCREENSHOT, [this](binary_output_stream& s) { + out.extension(TAG_SCREENSHOT, [this](binarystream::output& s) { s.blob_implicit(this->screenshot); }, true, screenshot.size()); for(auto i : sram) { - out.extension(TAG_SAVE_SRAM, [&i](binary_output_stream& s) { + out.extension(TAG_SAVE_SRAM, [&i](binarystream::output& s) { s.string(i.first); s.blob_implicit(i.second); }); } } - out.extension(TAG_GAMENAME, [this](binary_output_stream& s) { + out.extension(TAG_GAMENAME, [this](binarystream::output& s) { s.string_implicit(this->gamename); }); for(auto i : subtitles) - out.extension(TAG_SUBTITLE, [&i](binary_output_stream& s) { + out.extension(TAG_SUBTITLE, [&i](binarystream::output& s) { s.number(i.first.get_frame()); s.number(i.first.get_length()); s.string_implicit(i.second); }); for(auto i : authors) - out.extension(TAG_AUTHOR, [&i](binary_output_stream& s) { + out.extension(TAG_AUTHOR, [&i](binarystream::output& s) { s.string(i.first); s.string_implicit(i.second); }); for(auto i : active_macros) - out.extension(TAG_MACRO, [&i](binary_output_stream& s) { + out.extension(TAG_MACRO, [&i](binarystream::output& s) { s.number(i.second); s.string_implicit(i.first); }); for(auto i : ramcontent) { - out.extension(TAG_RAMCONTENT, [&i](binary_output_stream& s) { + out.extension(TAG_RAMCONTENT, [&i](binarystream::output& s) { s.string(i.first); s.blob_implicit(i.second); }); @@ -923,7 +923,7 @@ void moviefile::binary_io(std::ostream& _stream) throw(std::bad_alloc, std::runt void moviefile::binary_io(std::istream& _stream, core_type& romtype) throw(std::bad_alloc, std::runtime_error) { - binary_input_stream in(_stream); + binarystream::input in(_stream); std::string tmp = in.string(); try { gametype = &romtype.lookup_sysregion(tmp); @@ -941,35 +941,35 @@ void moviefile::binary_io(std::istream& _stream, core_type& romtype) throw(std:: input.clear(ports); in.extension({ - {TAG_ANCHOR_SAVE, [this](binary_input_stream& s) { + {TAG_ANCHOR_SAVE, [this](binarystream::input& s) { s.blob_implicit(this->anchor_savestate); - }},{TAG_AUTHOR, [this](binary_input_stream& s) { + }},{TAG_AUTHOR, [this](binarystream::input& s) { std::string a = s.string(); std::string b = s.string_implicit(); this->authors.push_back(std::make_pair(a, b)); - }},{TAG_CORE_VERSION, [this](binary_input_stream& s) { + }},{TAG_CORE_VERSION, [this](binarystream::input& s) { this->coreversion = s.string_implicit(); - }},{TAG_GAMENAME, [this](binary_input_stream& s) { + }},{TAG_GAMENAME, [this](binarystream::input& s) { this->gamename = s.string_implicit(); - }},{TAG_HOSTMEMORY, [this](binary_input_stream& s) { + }},{TAG_HOSTMEMORY, [this](binarystream::input& s) { s.blob_implicit(this->host_memory); - }},{TAG_MACRO, [this](binary_input_stream& s) { + }},{TAG_MACRO, [this](binarystream::input& s) { uint64_t n = s.number(); this->active_macros[s.string_implicit()] = n; - }},{TAG_MOVIE, [this](binary_input_stream& s) { + }},{TAG_MOVIE, [this](binarystream::input& s) { binary_read_movie(s, input); - }},{TAG_MOVIE_SRAM, [this](binary_input_stream& s) { + }},{TAG_MOVIE_SRAM, [this](binarystream::input& s) { std::string a = s.string(); s.blob_implicit(this->movie_sram[a]); - }},{TAG_RAMCONTENT, [this](binary_input_stream& s) { + }},{TAG_RAMCONTENT, [this](binarystream::input& s) { std::string a = s.string(); s.blob_implicit(this->ramcontent[a]); - }},{TAG_MOVIE_TIME, [this](binary_input_stream& s) { + }},{TAG_MOVIE_TIME, [this](binarystream::input& s) { this->movie_rtc_second = s.number(); this->movie_rtc_subsecond = s.number(); - }},{TAG_PROJECT_ID, [this](binary_input_stream& s) { + }},{TAG_PROJECT_ID, [this](binarystream::input& s) { this->projectid = s.string_implicit(); - }},{TAG_ROMHASH, [this](binary_input_stream& s) { + }},{TAG_ROMHASH, [this](binarystream::input& s) { uint8_t n = s.byte(); std::string h = s.string_implicit(); if(n > 2 * ROM_SLOT_COUNT) @@ -978,19 +978,19 @@ void moviefile::binary_io(std::istream& _stream, core_type& romtype) throw(std:: romxml_sha256[n >> 1] = h; else romimg_sha256[n >> 1] = h; - }},{TAG_ROMHINT, [this](binary_input_stream& s) { + }},{TAG_ROMHINT, [this](binarystream::input& s) { uint8_t n = s.byte(); std::string h = s.string_implicit(); if(n > ROM_SLOT_COUNT) return; namehint[n] = h; - }},{TAG_RRDATA, [this](binary_input_stream& s) { + }},{TAG_RRDATA, [this](binarystream::input& s) { s.blob_implicit(this->c_rrdata); this->rerecords = (stringfmt() << rrdata.count(c_rrdata)).str(); - }},{TAG_SAVE_SRAM, [this](binary_input_stream& s) { + }},{TAG_SAVE_SRAM, [this](binarystream::input& s) { std::string a = s.string(); s.blob_implicit(this->sram[a]); - }},{TAG_SAVESTATE, [this](binary_input_stream& s) { + }},{TAG_SAVESTATE, [this](binarystream::input& s) { this->is_savestate = true; this->save_frame = s.number(); this->lagged_frames = s.number(); @@ -1001,15 +1001,15 @@ void moviefile::binary_io(std::istream& _stream, core_type& romtype) throw(std:: i = s.number32(); this->poll_flag = (s.byte() != 0); s.blob_implicit(this->savestate); - }},{TAG_SCREENSHOT, [this](binary_input_stream& s) { + }},{TAG_SCREENSHOT, [this](binarystream::input& s) { s.blob_implicit(this->screenshot); - }},{TAG_SUBTITLE, [this](binary_input_stream& s) { + }},{TAG_SUBTITLE, [this](binarystream::input& s) { uint64_t f = s.number(); uint64_t l = s.number(); std::string x = s.string_implicit(); this->subtitles[moviefile_subtiming(f, l)] = x; }} - }, binary_null_default); + }, binarystream::null_default); } uint64_t moviefile::get_frame_count() throw() diff --git a/src/library/binarystream.cpp b/src/library/binarystream.cpp index f0f259c3..88e4ec70 100644 --- a/src/library/binarystream.cpp +++ b/src/library/binarystream.cpp @@ -6,24 +6,26 @@ #include #include +namespace binarystream +{ const uint32_t TAG_ = 0xaddb2d86; -binary_output_stream::binary_output_stream() +output::output() : strm(buf) { } -binary_output_stream::binary_output_stream(std::ostream& s) +output::output(std::ostream& s) : strm(s) { } -void binary_output_stream::byte(uint8_t byte) +void output::byte(uint8_t byte) { strm.write(reinterpret_cast(&byte), 1); } -void binary_output_stream::number(uint64_t number) +void output::number(uint64_t number) { char data[10]; size_t len = 0; @@ -35,7 +37,7 @@ void binary_output_stream::number(uint64_t number) strm.write(data, len); } -size_t binary_output_stream::numberbytes(uint64_t number) +size_t output::numberbytes(uint64_t number) { size_t o = 0; do { @@ -45,44 +47,44 @@ size_t binary_output_stream::numberbytes(uint64_t number) return o; } -void binary_output_stream::number32(uint32_t number) +void output::number32(uint32_t number) { char data[4]; write32ube(data, number); strm.write(data, 4); } -void binary_output_stream::string(const std::string& string) +void output::string(const std::string& string) { number(string.length()); std::copy(string.begin(), string.end(), std::ostream_iterator(strm)); } -void binary_output_stream::string_implicit(const std::string& string) +void output::string_implicit(const std::string& string) { std::copy(string.begin(), string.end(), std::ostream_iterator(strm)); } -void binary_output_stream::blob_implicit(const std::vector& blob) +void output::blob_implicit(const std::vector& blob) { strm.write(&blob[0], blob.size()); } -void binary_output_stream::raw(const void* buf, size_t bufsize) +void output::raw(const void* buf, size_t bufsize) { strm.write(reinterpret_cast(buf), bufsize); } -void binary_output_stream::write_extension_tag(uint32_t tag, uint64_t size) +void output::write_extension_tag(uint32_t tag, uint64_t size) { number32(TAG_); number32(tag); number(size); } -void binary_output_stream::extension(uint32_t tag, std::function fn, bool even_empty) +void output::extension(uint32_t tag, std::function fn, bool even_empty) { - binary_output_stream tmp; + output tmp; fn(tmp); std::string str = tmp.get(); if(!even_empty && !str.length()) @@ -92,7 +94,7 @@ void binary_output_stream::extension(uint32_t tag, std::function fn, bool even_empty, +void output::extension(uint32_t tag, std::function fn, bool even_empty, size_t size_precognition) { if(!even_empty && !size_precognition) @@ -104,21 +106,21 @@ void binary_output_stream::extension(uint32_t tag, std::function _r; @@ -148,10 +150,10 @@ std::string binary_input_stream::string() return r; } -std::string binary_input_stream::string_implicit() +std::string input::string_implicit() { if(!parent) - throw std::logic_error("binary_input_stream::string_implicit() can only be used in substreams"); + throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams"); std::vector _r; _r.resize(left); read(&_r[0], left); @@ -159,40 +161,40 @@ std::string binary_input_stream::string_implicit() return r; } -void binary_input_stream::blob_implicit(std::vector& blob) +void input::blob_implicit(std::vector& blob) { if(!parent) - throw std::logic_error("binary_input_stream::string_implicit() can only be used in substreams"); + throw std::logic_error("binarystream::input::string_implicit() can only be used in substreams"); blob.resize(left); read(&blob[0], left); } -binary_input_stream::binary_input_stream(std::istream& s) +input::input(std::istream& s) : strm(s), left(0), parent(NULL) { } -binary_input_stream::binary_input_stream(binary_input_stream& s, uint64_t len) +input::input(input& s, uint64_t len) : strm(s.strm), left(len), parent(&s) { if(parent->parent && left > parent->left) throw std::runtime_error("Substream length greater than its parent"); } -void binary_input_stream::raw(void* buf, size_t bufsize) +void input::raw(void* buf, size_t bufsize) { read(reinterpret_cast(buf), bufsize); } -void binary_input_stream::extension(std::function fn) +void input::extension(std::function fn) { extension({}, fn); } -void binary_input_stream::extension(std::initializer_list funcs, - std::function default_hdlr) +void input::extension(std::initializer_list funcs, + std::function default_hdlr) { - std::map> fn; + std::map> fn; for(auto i : funcs) fn[i.tag] = i.fn; while(!parent || left > 0) { @@ -204,7 +206,7 @@ void binary_input_stream::extension(std::initializer_list fu throw std::runtime_error("Binary file packet structure desync"); uint32_t tag = number32(); uint64_t size = number(); - binary_input_stream ss(*this, size); + input ss(*this, size); if(fn.count(tag)) fn[tag](ss); else @@ -213,16 +215,16 @@ void binary_input_stream::extension(std::initializer_list fu } } -void binary_input_stream::flush() +void input::flush() { if(!parent) - throw std::logic_error("binary_input_stream::flush() can only be used in substreams"); + throw std::logic_error("binarystream::input::flush() can only be used in substreams"); char buf[256]; while(left) read(buf, min(left, (uint64_t)256)); } -bool binary_input_stream::read(char* buf, size_t size, bool allow_none) +bool input::read(char* buf, size_t size, bool allow_none) { if(parent) { if(left == 0 && allow_none) @@ -242,7 +244,8 @@ bool binary_input_stream::read(char* buf, size_t size, bool allow_none) return true; } -void binary_null_default(uint32_t tag, binary_input_stream& s) +void null_default(uint32_t tag, input& s) { //no-op } +}