Convert DrivenEngine rlog/wlog to use BaseWriter
This commit is contained in:
@@ -213,100 +213,42 @@ inline static const char *action_string(DrvAction act) {
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class PlayLogfile : public std::ofstream { using std::ofstream::ofstream; };
|
class PlayLogfile : public BaseWriter<PlayLogfile>, public std::ofstream {
|
||||||
class ReplayLogfile : public std::ifstream { using std::ifstream::ifstream; };
|
using std::ofstream::ofstream;
|
||||||
|
public:
|
||||||
static uint8_t rlog_uint8(EngineWrapper *w) {
|
void write_bytes(const char *n, size_t size) { write(n, size); }
|
||||||
uint8_t result;
|
void raise_truncated() {
|
||||||
w->rlog->read((char *)&result, 1);
|
fprintf(stderr, "number exceeds allowable size\n");
|
||||||
if (!w->rlog->good()) return 0;
|
std::abort();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
assert (len <= DRV_SHORTSTRING_SIZE);
|
void write_short_string(std::string_view v) {
|
||||||
if (len > 0) w->rlog->read(w->databuffer, len);
|
assert(v.size() < DRV_SHORTSTRING_SIZE);
|
||||||
if (!w->rlog->good()) return std::string_view();
|
write_string(v);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
std::string result(len, ' ');
|
void write_cmd_hash(DrvAction act, uint32_t hash) {
|
||||||
if (len > 0) w->rlog->read(&result[0], len);
|
write_uint8(act);
|
||||||
if (!w->rlog->good()) return "";
|
write_uint32(hash);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
w->wlog->write(v.data(), v.size());
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static void wlog_string(EngineWrapper *w, std::string_view v) {
|
class ReplayLogfile : public BaseReader<ReplayLogfile>, public std::ifstream {
|
||||||
if (v.size() >= 255) {
|
using std::ifstream::ifstream;
|
||||||
wlog_uint8(w, 0xFF);
|
public:
|
||||||
wlog_uint32(w, v.size());
|
using read_string_type = std::string;
|
||||||
} else {
|
void read_bytes_into(char *n, size_t size) { read(n, size); }
|
||||||
wlog_uint8(w, v.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());
|
std::string_view read_short_string(EngineWrapper *w) {
|
||||||
}
|
size_t size = read_length();
|
||||||
|
assert(size <= DRV_SHORTSTRING_SIZE);
|
||||||
static void wlog_cmd_hash(EngineWrapper *w, DrvAction act, uint32_t hash) {
|
if (size > 0) read(w->databuffer, size);
|
||||||
wlog_uint8(w, act);
|
if (!good()) return std::string_view();
|
||||||
wlog_uint32(w, hash);
|
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) {
|
static void release(EngineWrapper *w) {
|
||||||
if (w->wlog != nullptr) {
|
if (w->wlog != nullptr) {
|
||||||
wlog_cmd_hash(w, PLAY_RELEASE, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_RELEASE, eng::memhash());
|
||||||
}
|
}
|
||||||
reset_wrapper(w, "");
|
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 we have a logfile, then log this initialization.
|
||||||
if (w->wlog != nullptr) {
|
if (w->wlog != nullptr) {
|
||||||
wlog_cmd_hash(w, PLAY_INITIALIZE, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_INITIALIZE, eng::memhash());
|
||||||
wlog_uint32(w, argc);
|
w->wlog->write_uint32(argc);
|
||||||
for (uint32_t i = 0; i < argc; i++) {
|
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();
|
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) {
|
static void replay_initialize(EngineWrapper *w) {
|
||||||
assert(w->rlog != nullptr);
|
assert(w->rlog != nullptr);
|
||||||
std::vector<std::string> argvstr;
|
std::vector<std::string> argvstr;
|
||||||
uint32_t argc = rlog_uint32(w);
|
uint32_t argc = w->rlog->read_uint32();
|
||||||
for (uint32_t i = 0; i < argc; i++) {
|
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()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "replay log corrupt in replay_initialize");
|
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) {
|
static void play_clear_new_outgoing(EngineWrapper *w) {
|
||||||
assert(w->rlog == nullptr);
|
assert(w->rlog == nullptr);
|
||||||
if (w->wlog != 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->wlog->flush();
|
||||||
}
|
}
|
||||||
w->engine->drv_clear_new_outgoing();
|
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;
|
uint32_t ndata; const char *data;
|
||||||
w->engine->drv_get_outgoing(chid, &ndata, &data);
|
w->engine->drv_get_outgoing(chid, &ndata, &data);
|
||||||
assert(nbytes <= ndata);
|
assert(nbytes <= ndata);
|
||||||
wlog_cmd_hash(w, PLAY_SENT_OUTGOING, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_SENT_OUTGOING, eng::memhash());
|
||||||
wlog_uint32(w, chid);
|
w->wlog->write_uint32(chid);
|
||||||
wlog_uint32(w, nbytes);
|
w->wlog->write_uint32(nbytes);
|
||||||
wlog_uint64(w, SpookyHash::QkHash64(data, nbytes));
|
w->wlog->write_uint64(SpookyHash::QkHash64(data, nbytes));
|
||||||
w->wlog->flush();
|
w->wlog->flush();
|
||||||
}
|
}
|
||||||
w->engine->drv_sent_outgoing(chid, nbytes);
|
w->engine->drv_sent_outgoing(chid, nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void replay_sent_outgoing(EngineWrapper *w) {
|
static void replay_sent_outgoing(EngineWrapper *w) {
|
||||||
uint32_t chid = rlog_uint32(w);
|
uint32_t chid = w->rlog->read_uint32();
|
||||||
uint32_t nbytes = rlog_uint32(w);
|
uint32_t nbytes = w->rlog->read_uint32();
|
||||||
uint64_t hash = rlog_uint64(w);
|
uint64_t hash = w->rlog->read_uint64();
|
||||||
|
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "replay log corrupt in replay_sent_outgoing");
|
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) {
|
static void play_recv_incoming(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) {
|
||||||
assert(w->rlog == nullptr);
|
assert(w->rlog == nullptr);
|
||||||
if (w->wlog != nullptr) {
|
if (w->wlog != nullptr) {
|
||||||
wlog_cmd_hash(w, PLAY_RECV_INCOMING, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_RECV_INCOMING, eng::memhash());
|
||||||
wlog_uint32(w, chid);
|
w->wlog->write_uint32(chid);
|
||||||
wlog_short_string(w, std::string_view(data, len));
|
w->wlog->write_short_string(std::string_view(data, len));
|
||||||
w->wlog->flush();
|
w->wlog->flush();
|
||||||
}
|
}
|
||||||
w->engine->drv_recv_incoming(chid, len, data);
|
w->engine->drv_recv_incoming(chid, len, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void replay_recv_incoming(EngineWrapper *w) {
|
static void replay_recv_incoming(EngineWrapper *w) {
|
||||||
uint32_t chid = rlog_uint32(w);
|
uint32_t chid = w->rlog->read_uint32();
|
||||||
std::string_view data = rlog_short_string(w);
|
std::string_view data = w->rlog->read_short_string(w);
|
||||||
|
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "replay log corrupt in replay_recv_incoming");
|
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) {
|
static void play_notify_close(EngineWrapper *w, uint32_t chid, uint32_t len, const char *data) {
|
||||||
assert(w->rlog == nullptr);
|
assert(w->rlog == nullptr);
|
||||||
if (w->wlog != nullptr) {
|
if (w->wlog != nullptr) {
|
||||||
wlog_cmd_hash(w, PLAY_NOTIFY_CLOSE, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_NOTIFY_CLOSE, eng::memhash());
|
||||||
wlog_uint32(w, chid);
|
w->wlog->write_uint32(chid);
|
||||||
wlog_string(w, std::string_view(data, len));
|
w->wlog->write_string(std::string_view(data, len));
|
||||||
w->wlog->flush();
|
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) {
|
static void replay_notify_close(EngineWrapper *w) {
|
||||||
uint32_t chid = rlog_uint32(w);
|
uint32_t chid = w->rlog->read_uint32();
|
||||||
std::string message = rlog_string(w);
|
std::string message = w->rlog->read_string();
|
||||||
|
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "replay log corrupt in replay_notify_close");
|
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) {
|
static uint32_t play_notify_accept(EngineWrapper *w, uint32_t port) {
|
||||||
assert(w->rlog == nullptr);
|
assert(w->rlog == nullptr);
|
||||||
if (w->wlog != nullptr) {
|
if (w->wlog != nullptr) {
|
||||||
wlog_cmd_hash(w, PLAY_NOTIFY_ACCEPT, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_NOTIFY_ACCEPT, eng::memhash());
|
||||||
wlog_uint32(w, port);
|
w->wlog->write_uint32(port);
|
||||||
w->wlog->flush();
|
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) {
|
static void replay_notify_accept(EngineWrapper *w) {
|
||||||
uint32_t port = rlog_uint32(w);
|
uint32_t port = w->rlog->read_uint32();
|
||||||
|
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "replay log corrupt in replay_notify_accept");
|
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) {
|
static void play_invoke_event_update(EngineWrapper *w, double clock) {
|
||||||
assert(w->rlog == nullptr);
|
assert(w->rlog == nullptr);
|
||||||
if (w->wlog != nullptr) {
|
if (w->wlog != nullptr) {
|
||||||
wlog_cmd_hash(w, PLAY_INVOKE_EVENT_UPDATE, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_INVOKE_EVENT_UPDATE, eng::memhash());
|
||||||
wlog_double(w, clock);
|
w->wlog->write_double(clock);
|
||||||
w->wlog->flush();
|
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) {
|
static void replay_invoke_event_update(EngineWrapper *w) {
|
||||||
double clock = rlog_double(w);
|
double clock = w->rlog->read_double();
|
||||||
|
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "replay log corrupt in replay_event_update");
|
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) {
|
void play_set_lua_source(EngineWrapper *w, uint32_t srcpklen, const char *srcpk) {
|
||||||
assert(w->rlog == nullptr);
|
assert(w->rlog == nullptr);
|
||||||
if (w->wlog != nullptr) {
|
if (w->wlog != nullptr) {
|
||||||
wlog_cmd_hash(w, PLAY_SET_LUA_SOURCE, eng::memhash());
|
w->wlog->write_cmd_hash(PLAY_SET_LUA_SOURCE, eng::memhash());
|
||||||
wlog_string(w, std::string_view(srcpk, srcpklen));
|
w->wlog->write_string(std::string_view(srcpk, srcpklen));
|
||||||
w->wlog->flush();
|
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) {
|
void replay_set_lua_source(EngineWrapper *w) {
|
||||||
std::string srcpack = rlog_string(w);
|
std::string srcpack = w->rlog->read_string();
|
||||||
|
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "replay log corrupt in replay_set_lua_source");
|
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.
|
// Read one step from the logfile, and make sure it's an initialize step.
|
||||||
uint8_t code = rlog_uint8(w);
|
uint8_t code = w->rlog->read_uint8();
|
||||||
int hash = rlog_uint32(w);
|
int hash = w->rlog->read_uint32();
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "logfile corrupt in initial step");
|
return reset_wrapper(w, "logfile corrupt in initial step");
|
||||||
}
|
}
|
||||||
@@ -924,11 +865,11 @@ static void replaycore_step(EngineWrapper *w) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t code = rlog_uint8(w);
|
uint8_t code = w->rlog->read_uint8();
|
||||||
if (w->rlog->eof()) {
|
if (w->rlog->eof()) {
|
||||||
return reset_wrapper(w, "logfile terminated abruptly");
|
return reset_wrapper(w, "logfile terminated abruptly");
|
||||||
}
|
}
|
||||||
int hash = rlog_uint32(w);
|
int hash = w->rlog->read_uint32();
|
||||||
if (!w->rlog->good()) {
|
if (!w->rlog->good()) {
|
||||||
return reset_wrapper(w, "logfile corrupt in replay step");
|
return reset_wrapper(w, "logfile corrupt in replay step");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -381,7 +381,11 @@ public:
|
|||||||
// Throw a StreamCorruption exception.
|
// Throw a StreamCorruption exception.
|
||||||
void raise_truncated() { throw StreamCorruption(); }
|
void raise_truncated() { throw StreamCorruption(); }
|
||||||
void raise_string_too_long() { 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:
|
private:
|
||||||
// Start and end of the allocated block.
|
// Start and end of the allocated block.
|
||||||
char *buf_lo_;
|
char *buf_lo_;
|
||||||
|
|||||||
@@ -31,14 +31,13 @@
|
|||||||
// void write_length(size_t data)
|
// void write_length(size_t data)
|
||||||
// void write_string(std::string_view 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<DerivedWriter>
|
// class DerivedWriter : public BaseWriter<DerivedWriter>
|
||||||
//
|
//
|
||||||
// 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)
|
// write_bytes(const char *n, size_t size)
|
||||||
//
|
|
||||||
// raise_truncated()
|
// raise_truncated()
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
@@ -111,15 +110,16 @@ public:
|
|||||||
// String read_string_limit(uint64_t size);
|
// String read_string_limit(uint64_t size);
|
||||||
// String read_string();
|
// 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<DerivedReader>
|
// class DerivedReader : public BaseReader<DerivedReader>
|
||||||
//
|
//
|
||||||
// The derived class must provide:
|
// 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 read_bytes_into(char *n, size_t size)
|
||||||
// void raise_string_too_long();
|
// void raise_string_too_long();
|
||||||
|
// bool read_beyond_eof();
|
||||||
//
|
//
|
||||||
///////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@@ -129,7 +129,9 @@ protected:
|
|||||||
template<class T>
|
template<class T>
|
||||||
T read_value_core() {
|
T read_value_core() {
|
||||||
T result;
|
T result;
|
||||||
static_cast<Derived*>(this)->read_bytes_into((char *)(&result), sizeof(result));
|
Derived *dthis = static_cast<Derived*>(this);
|
||||||
|
dthis->read_bytes_into((char *)(&result), sizeof(result));
|
||||||
|
if (dthis->read_beyond_eof()) result = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +161,11 @@ public:
|
|||||||
|
|
||||||
auto read_string_limit(uint64_t limit) {
|
auto read_string_limit(uint64_t limit) {
|
||||||
size_t len = read_length();
|
size_t len = read_length();
|
||||||
if (len > limit) static_cast<Derived*>(this)->raise_string_too_long();
|
Derived *dthis = static_cast<Derived*>(this);
|
||||||
|
if (len > limit) dthis->raise_string_too_long();
|
||||||
typename Derived::read_string_type result(len, ' ');
|
typename Derived::read_string_type result(len, ' ');
|
||||||
static_cast<Derived*>(this)->read_bytes_into(&(result[0]), len);
|
dthis->read_bytes_into(&(result[0]), len);
|
||||||
|
if (dthis->read_beyond_eof()) result.clear();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user