diff --git a/luprex/cpp/core/drivenengine.cpp b/luprex/cpp/core/drivenengine.cpp index 3dacc31f..75b9047c 100644 --- a/luprex/cpp/core/drivenengine.cpp +++ b/luprex/cpp/core/drivenengine.cpp @@ -213,100 +213,42 @@ inline static const char *action_string(DrvAction act) { ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -class PlayLogfile : public std::ofstream { using std::ofstream::ofstream; }; -class ReplayLogfile : public std::ifstream { using std::ifstream::ifstream; }; - -static uint8_t rlog_uint8(EngineWrapper *w) { - uint8_t result; - w->rlog->read((char *)&result, 1); - if (!w->rlog->good()) return 0; - return result; -} - -static uint32_t rlog_uint32(EngineWrapper *w) { - uint32_t result; - w->rlog->read((char *)&result, 4); - if (!w->rlog->good()) return 0; - return result; -} - -static uint64_t rlog_uint64(EngineWrapper *w) { - uint64_t result; - w->rlog->read((char *)&result, 8); - if (!w->rlog->good()) return 0; - return result; -} - -static double rlog_double(EngineWrapper *w) { - double result; - w->rlog->read((char *)&result, 8); - if (!w->rlog->good()) return 0.0; - return result; -} - -std::string_view rlog_short_string(EngineWrapper *w) { - uint32_t len = rlog_uint8(w); - if (len == 255) { - len = rlog_uint32(w); +class PlayLogfile : public BaseWriter, public std::ofstream { + using std::ofstream::ofstream; +public: + void write_bytes(const char *n, size_t size) { write(n, size); } + void raise_truncated() { + fprintf(stderr, "number exceeds allowable size\n"); + std::abort(); } - assert (len <= DRV_SHORTSTRING_SIZE); - if (len > 0) w->rlog->read(w->databuffer, len); - if (!w->rlog->good()) return std::string_view(); - return std::string_view(w->databuffer, len); -} - -std::string rlog_string(EngineWrapper *w) { - uint32_t len = rlog_uint8(w); - if (len == 255) { - len = rlog_uint32(w); + void write_short_string(std::string_view v) { + assert(v.size() < DRV_SHORTSTRING_SIZE); + write_string(v); } - std::string result(len, ' '); - if (len > 0) w->rlog->read(&result[0], len); - if (!w->rlog->good()) return ""; - return result; -} - -static void wlog_uint8(EngineWrapper *w, uint8_t v) { - w->wlog->put((char)v); -} - -static void wlog_uint32(EngineWrapper *w, uint32_t v) { - w->wlog->write((const char *)&v, 4); -} - -static void wlog_uint64(EngineWrapper *w, uint64_t v) { - w->wlog->write((const char *)&v, 8); -} - -static void wlog_double(EngineWrapper *w, double v) { - w->wlog->write((const char *)&v, 8); -} - -static void wlog_short_string(EngineWrapper *w, std::string_view v) { - assert (v.size() <= DRV_SHORTSTRING_SIZE); - if (v.size() >= 255) { - wlog_uint8(w, 0xFF); - wlog_uint32(w, v.size()); - } else { - wlog_uint8(w, v.size()); + void write_cmd_hash(DrvAction act, uint32_t hash) { + write_uint8(act); + write_uint32(hash); } - w->wlog->write(v.data(), v.size()); -} +}; -static void wlog_string(EngineWrapper *w, std::string_view v) { - if (v.size() >= 255) { - wlog_uint8(w, 0xFF); - wlog_uint32(w, v.size()); - } else { - wlog_uint8(w, v.size()); +class ReplayLogfile : public BaseReader, public std::ifstream { + using std::ifstream::ifstream; +public: + using read_string_type = std::string; + void read_bytes_into(char *n, size_t size) { read(n, size); } + bool read_beyond_eof() { return !good(); } + void raise_string_too_long() { + fprintf(stderr, "string in logfile is too long"); + std::abort(); } - w->wlog->write(v.data(), v.size()); -} - -static void wlog_cmd_hash(EngineWrapper *w, DrvAction act, uint32_t hash) { - wlog_uint8(w, act); - wlog_uint32(w, hash); -} + std::string_view read_short_string(EngineWrapper *w) { + size_t size = read_length(); + assert(size <= DRV_SHORTSTRING_SIZE); + if (size > 0) read(w->databuffer, size); + if (!good()) return std::string_view(); + return std::string_view(w->databuffer, size); + } +}; ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -350,7 +292,7 @@ static void reset_wrapper(EngineWrapper *w, const char *format, ...) { static void release(EngineWrapper *w) { if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_RELEASE, eng::memhash()); + w->wlog->write_cmd_hash(PLAY_RELEASE, eng::memhash()); } reset_wrapper(w, ""); }; @@ -630,12 +572,12 @@ static void play_initialize(EngineWrapper *w, uint32_t argc, char **argv, uint32 // If we have a logfile, then log this initialization. if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_INITIALIZE, eng::memhash()); - wlog_uint32(w, argc); + w->wlog->write_cmd_hash(PLAY_INITIALIZE, eng::memhash()); + w->wlog->write_uint32(argc); for (uint32_t i = 0; i < argc; i++) { - wlog_string(w, argv[i]); + w->wlog->write_string(argv[i]); } - wlog_string(w, std::string_view(srcpk, srcpklen)); + w->wlog->write_string(std::string_view(srcpk, srcpklen)); w->wlog->flush(); } @@ -662,11 +604,11 @@ static void play_initialize(EngineWrapper *w, uint32_t argc, char **argv, uint32 static void replay_initialize(EngineWrapper *w) { assert(w->rlog != nullptr); std::vector argvstr; - uint32_t argc = rlog_uint32(w); + uint32_t argc = w->rlog->read_uint32(); for (uint32_t i = 0; i < argc; i++) { - argvstr.push_back(rlog_string(w)); + argvstr.push_back(w->rlog->read_string()); } - std::string srcpk = rlog_string(w); + std::string srcpk = w->rlog->read_string(); if (!w->rlog->good()) { return reset_wrapper(w, "replay log corrupt in replay_initialize"); @@ -697,7 +639,7 @@ static void replay_initialize(EngineWrapper *w) { static void play_clear_new_outgoing(EngineWrapper *w) { assert(w->rlog == nullptr); if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_CLEAR_NEW_OUTGOING, eng::memhash()); + w->wlog->write_cmd_hash(PLAY_CLEAR_NEW_OUTGOING, eng::memhash()); w->wlog->flush(); } w->engine->drv_clear_new_outgoing(); @@ -717,19 +659,19 @@ static void play_sent_outgoing(EngineWrapper *w, uint32_t chid, uint32_t nbytes) uint32_t ndata; const char *data; w->engine->drv_get_outgoing(chid, &ndata, &data); assert(nbytes <= ndata); - wlog_cmd_hash(w, PLAY_SENT_OUTGOING, eng::memhash()); - wlog_uint32(w, chid); - wlog_uint32(w, nbytes); - wlog_uint64(w, SpookyHash::QkHash64(data, nbytes)); + w->wlog->write_cmd_hash(PLAY_SENT_OUTGOING, eng::memhash()); + w->wlog->write_uint32(chid); + w->wlog->write_uint32(nbytes); + w->wlog->write_uint64(SpookyHash::QkHash64(data, nbytes)); w->wlog->flush(); } w->engine->drv_sent_outgoing(chid, nbytes); } static void replay_sent_outgoing(EngineWrapper *w) { - uint32_t chid = rlog_uint32(w); - uint32_t nbytes = rlog_uint32(w); - uint64_t hash = rlog_uint64(w); + uint32_t chid = w->rlog->read_uint32(); + uint32_t nbytes = w->rlog->read_uint32(); + uint64_t hash = w->rlog->read_uint64(); if (!w->rlog->good()) { return reset_wrapper(w, "replay log corrupt in replay_sent_outgoing"); @@ -753,18 +695,18 @@ static void replay_sent_outgoing(EngineWrapper *w) { static void play_recv_incoming(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) { assert(w->rlog == nullptr); if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_RECV_INCOMING, eng::memhash()); - wlog_uint32(w, chid); - wlog_short_string(w, std::string_view(data, len)); + w->wlog->write_cmd_hash(PLAY_RECV_INCOMING, eng::memhash()); + w->wlog->write_uint32(chid); + w->wlog->write_short_string(std::string_view(data, len)); w->wlog->flush(); } w->engine->drv_recv_incoming(chid, len, data); } static void replay_recv_incoming(EngineWrapper *w) { - uint32_t chid = rlog_uint32(w); - std::string_view data = rlog_short_string(w); - + uint32_t chid = w->rlog->read_uint32(); + std::string_view data = w->rlog->read_short_string(w); + if (!w->rlog->good()) { return reset_wrapper(w, "replay log corrupt in replay_recv_incoming"); } @@ -779,9 +721,9 @@ static void replay_recv_incoming(EngineWrapper *w) { static void play_notify_close(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) { assert(w->rlog == nullptr); if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_NOTIFY_CLOSE, eng::memhash()); - wlog_uint32(w, chid); - wlog_string(w, std::string_view(data, len)); + w->wlog->write_cmd_hash(PLAY_NOTIFY_CLOSE, eng::memhash()); + w->wlog->write_uint32(chid); + w->wlog->write_string(std::string_view(data, len)); w->wlog->flush(); } @@ -789,8 +731,8 @@ static void play_notify_close(EngineWrapper *w, uint32_t chid, uint32_t len, con } static void replay_notify_close(EngineWrapper *w) { - uint32_t chid = rlog_uint32(w); - std::string message = rlog_string(w); + uint32_t chid = w->rlog->read_uint32(); + std::string message = w->rlog->read_string(); if (!w->rlog->good()) { return reset_wrapper(w, "replay log corrupt in replay_notify_close"); @@ -806,8 +748,8 @@ static void replay_notify_close(EngineWrapper *w) { static uint32_t play_notify_accept(EngineWrapper *w, uint32_t port) { assert(w->rlog == nullptr); if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_NOTIFY_ACCEPT, eng::memhash()); - wlog_uint32(w, port); + w->wlog->write_cmd_hash(PLAY_NOTIFY_ACCEPT, eng::memhash()); + w->wlog->write_uint32(port); w->wlog->flush(); } @@ -815,7 +757,7 @@ static uint32_t play_notify_accept(EngineWrapper *w, uint32_t port) { } static void replay_notify_accept(EngineWrapper *w) { - uint32_t port = rlog_uint32(w); + uint32_t port = w->rlog->read_uint32(); if (!w->rlog->good()) { return reset_wrapper(w, "replay log corrupt in replay_notify_accept"); @@ -831,8 +773,8 @@ static void replay_notify_accept(EngineWrapper *w) { static void play_invoke_event_update(EngineWrapper *w, double clock) { assert(w->rlog == nullptr); if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_INVOKE_EVENT_UPDATE, eng::memhash()); - wlog_double(w, clock); + w->wlog->write_cmd_hash(PLAY_INVOKE_EVENT_UPDATE, eng::memhash()); + w->wlog->write_double(clock); w->wlog->flush(); } @@ -840,8 +782,7 @@ static void play_invoke_event_update(EngineWrapper *w, double clock) { } static void replay_invoke_event_update(EngineWrapper *w) { - double clock = rlog_double(w); - + double clock = w->rlog->read_double(); if (!w->rlog->good()) { return reset_wrapper(w, "replay log corrupt in replay_event_update"); } @@ -856,8 +797,8 @@ static void replay_invoke_event_update(EngineWrapper *w) { void play_set_lua_source(EngineWrapper *w, uint32_t srcpklen, const char *srcpk) { assert(w->rlog == nullptr); if (w->wlog != nullptr) { - wlog_cmd_hash(w, PLAY_SET_LUA_SOURCE, eng::memhash()); - wlog_string(w, std::string_view(srcpk, srcpklen)); + w->wlog->write_cmd_hash(PLAY_SET_LUA_SOURCE, eng::memhash()); + w->wlog->write_string(std::string_view(srcpk, srcpklen)); w->wlog->flush(); } @@ -865,7 +806,7 @@ void play_set_lua_source(EngineWrapper *w, uint32_t srcpklen, const char *srcpk) } void replay_set_lua_source(EngineWrapper *w) { - std::string srcpack = rlog_string(w); + std::string srcpack = w->rlog->read_string(); if (!w->rlog->good()) { return reset_wrapper(w, "replay log corrupt in replay_set_lua_source"); @@ -900,8 +841,8 @@ static void replaycore_initialize(EngineWrapper *w, const char *logfn) { } // Read one step from the logfile, and make sure it's an initialize step. - uint8_t code = rlog_uint8(w); - int hash = rlog_uint32(w); + uint8_t code = w->rlog->read_uint8(); + int hash = w->rlog->read_uint32(); if (!w->rlog->good()) { return reset_wrapper(w, "logfile corrupt in initial step"); } @@ -924,11 +865,11 @@ static void replaycore_step(EngineWrapper *w) { return; } - uint8_t code = rlog_uint8(w); + uint8_t code = w->rlog->read_uint8(); if (w->rlog->eof()) { return reset_wrapper(w, "logfile terminated abruptly"); } - int hash = rlog_uint32(w); + int hash = w->rlog->read_uint32(); if (!w->rlog->good()) { return reset_wrapper(w, "logfile corrupt in replay step"); } diff --git a/luprex/cpp/core/streambuffer.hpp b/luprex/cpp/core/streambuffer.hpp index 5355512c..721bd402 100644 --- a/luprex/cpp/core/streambuffer.hpp +++ b/luprex/cpp/core/streambuffer.hpp @@ -381,7 +381,11 @@ public: // Throw a StreamCorruption exception. void raise_truncated() { throw StreamCorruption(); } void raise_string_too_long() { throw StreamCorruption(); } - + + // This is always false, because this module throws exceptions + // when reading beyond EOF. + bool read_beyond_eof() { return false; } + private: // Start and end of the allocated block. char *buf_lo_; diff --git a/luprex/ext/base-writer.hpp b/luprex/ext/base-writer.hpp index f44c9462..8156dd5f 100644 --- a/luprex/ext/base-writer.hpp +++ b/luprex/ext/base-writer.hpp @@ -31,14 +31,13 @@ // void write_length(size_t data) // void write_string(std::string_view data) // -// In order to derive from BaseWriter, you must use the CRTP pattern: +// You should derive from BaseWriter using the CRTP pattern: // // class DerivedWriter : public BaseWriter // -// And you must provide two methods in the derived class: +// You must provide two methods in the derived class: // // write_bytes(const char *n, size_t size) -// // raise_truncated() // /////////////////////////////////////////////////////////////// @@ -111,15 +110,16 @@ public: // String read_string_limit(uint64_t size); // String read_string(); // -// In order to derive from BaseReader, you must use the CRTP pattern: +// You should derive from BaseReader using the CRTP pattern: // // class DerivedReader : public BaseReader // // The derived class must provide: // -// using read_string_type = std::string; // or similar +// using read_string_type = std::string; // or compatible // void read_bytes_into(char *n, size_t size) // void raise_string_too_long(); +// bool read_beyond_eof(); // /////////////////////////////////////////////////////////////// @@ -129,7 +129,9 @@ protected: template T read_value_core() { T result; - static_cast(this)->read_bytes_into((char *)(&result), sizeof(result)); + Derived *dthis = static_cast(this); + dthis->read_bytes_into((char *)(&result), sizeof(result)); + if (dthis->read_beyond_eof()) result = 0; return result; } @@ -159,9 +161,11 @@ public: auto read_string_limit(uint64_t limit) { size_t len = read_length(); - if (len > limit) static_cast(this)->raise_string_too_long(); + Derived *dthis = static_cast(this); + if (len > limit) dthis->raise_string_too_long(); typename Derived::read_string_type result(len, ' '); - static_cast(this)->read_bytes_into(&(result[0]), len); + dthis->read_bytes_into(&(result[0]), len); + if (dthis->read_beyond_eof()) result.clear(); return result; }