Created
September 7, 2014 18:49
-
-
Save reiver-dev/45057793a99d1506131e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef DECODER_HPP_ | |
#define DECODER_HPP_ | |
#include "streambuf.hpp" | |
#include "client_messages.hpp" | |
class Decoder { | |
public: | |
Decoder(size_t capacity) | |
{ | |
m_data.reset(new uint8_t[capacity]); | |
m_buf.reset_data(m_data.get(), capacity); | |
m_payload = nullptr; | |
} | |
bool advance(size_t len) | |
{ | |
if (m_state.is_completed()) | |
return true; | |
m_buf.in_commit(len); | |
while (m_state.step(this)) { | |
if (m_state.is_completed()) { | |
return true; | |
} | |
} | |
return false; | |
} | |
void reset() | |
{ | |
m_payload = nullptr; | |
m_state.next(&Decoder::initial_state); | |
m_buf.reset(); | |
} | |
const ClientMessages::Header& get_header() const | |
{ | |
return m_header; | |
} | |
const uint8_t* get_payload() const | |
{ | |
return m_payload; | |
} | |
void get_buffer(uint8_t **data, size_t *len) | |
{ | |
*data = m_buf.in_begin(); | |
*len = m_buf.in_len(); | |
} | |
private: | |
class State { | |
public: | |
using MemPtr = bool (Decoder::*)(); | |
State() : m_state(&Decoder::initial_state) | |
{ | |
// | |
} | |
bool step(Decoder *decoder) | |
{ | |
return (decoder->*m_state)(); | |
} | |
bool is_completed() | |
{ | |
return !m_state; | |
} | |
void complete() | |
{ | |
m_state = nullptr; | |
} | |
void next(MemPtr ptr) | |
{ | |
m_state = ptr; | |
} | |
private: | |
MemPtr m_state; | |
}; | |
bool header_ready() | |
{ | |
if (m_buf.out_len() >= m_header.len) | |
return false; | |
m_payload = m_buf.out_begin(); | |
m_state.complete(); | |
return true; | |
} | |
bool signature_ready() | |
{ | |
if (m_buf.out_len() < sizeof(ClientMessages::Header)) | |
return false; | |
ClientMessages::Header header, *hdata; | |
hdata = reinterpret_cast<ClientMessages::Header *>(m_buf.out_begin()); | |
header.sig = hdata->sig; | |
header.len = ntohl(hdata->len); | |
header.type = ntohl(hdata->type); | |
if (header.len <= m_buf.in_len()) { | |
m_header = header; | |
m_buf.out_commit(sizeof(m_header)); | |
m_state.next(&Decoder::header_ready); | |
} else { | |
reset(); | |
} | |
return true; | |
} | |
bool initial_state() | |
{ | |
m_payload = nullptr; | |
if (m_buf.out_len() < 2) | |
return false; | |
if (!memcmp(m_buf.out_begin(), &ClientMessages::SIGNATURE, sizeof(ClientMessages::SIGNATURE))) { | |
m_state.next(&Decoder::signature_ready); | |
} else { | |
reset(); | |
} | |
return true; | |
} | |
std::unique_ptr<uint8_t> m_data; | |
State m_state; | |
StreamBuf m_buf; | |
ClientMessages::Header m_header; | |
uint8_t *m_payload; | |
}; | |
#endif /* DECODER_HPP_ */ | |
#ifndef STREAMBUF_HPP | |
#define STREAMBUF_HPP | |
#include <cstring> | |
using std::size_t; | |
class StreamBuf | |
{ | |
public: | |
typedef uint8_t val_t; | |
StreamBuf() = default; | |
StreamBuf(void *data, size_t len) | |
: m_begin(static_cast<uint8_t *>(data)), | |
m_end(m_begin + len), | |
m_in(m_begin), | |
m_out(m_begin) | |
{ | |
// | |
} | |
StreamBuf(const StreamBuf&) = delete; | |
StreamBuf& operator=(const StreamBuf&) = delete; | |
StreamBuf(StreamBuf&&) = default; | |
StreamBuf& operator=(StreamBuf&&) = default; | |
// read operations | |
const val_t* out_begin() const { | |
return m_out; | |
} | |
val_t* out_begin() { | |
return m_out; | |
} | |
const val_t* out_end() const { | |
return m_in; | |
} | |
size_t out_len() const { | |
return m_in - m_out; | |
} | |
void out_commit(size_t bytes) { | |
m_out += bytes; | |
} | |
// write operations | |
val_t* in_begin() { | |
return m_in; | |
} | |
val_t* in_end() { | |
return m_end; | |
} | |
size_t in_len() const { | |
return m_end - m_in; | |
} | |
void in_commit(size_t bytes) { | |
m_in += bytes; | |
} | |
// state operations | |
void reset() { | |
m_out = m_in = m_begin; | |
} | |
void reset_data(val_t *data, size_t len) { | |
m_begin = static_cast<uint8_t *>(data); | |
m_end = m_begin + len; | |
reset(); | |
} | |
void rearrange() { | |
size_t rd = out_len(); | |
if (rd > 0) { | |
memmove(m_begin, m_out, rd); | |
} | |
m_out = m_begin; | |
m_in = m_begin + rd; | |
} | |
private: | |
val_t* m_begin; | |
val_t* m_end; | |
val_t* m_in; | |
val_t* m_out; | |
}; | |
#endif // STREAMBUF_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment