diff --git a/src/nt_messagereader.cpp b/src/nt_messagereader.cpp index 5ad3a5df57..f22d9ff1d2 100644 --- a/src/nt_messagereader.cpp +++ b/src/nt_messagereader.cpp @@ -24,30 +24,13 @@ MessageHandler::anchor() MessageReader::MessageReader(MessageHandler &handler, raw_istream& is, unsigned int proto_rev) - : m_handler(handler) - , m_is(is) + : WireDecoder(is, proto_rev) + , m_handler(handler) { - m_allocated = 1024; - m_buf = (char *)std::malloc(m_allocated); - m_proto_rev = proto_rev; - m_error = 0; } MessageReader::~MessageReader() { - std::free(m_buf); -} - -void -MessageReader::Realloc(std::size_t len) -{ - if (m_allocated >= len) - return; - std::size_t newlen = m_allocated * 2; - while (newlen < len) - newlen *= 2; - m_buf = (char *)std::realloc(m_buf, newlen); - m_allocated = newlen; } bool @@ -191,7 +174,8 @@ MessageReader::Run() if (!Read16(&uid)) return false; unsigned long size; if (!ReadULEB128(&size)) return false; - if (!Read(size)) return false; + char *buf; + if (!Read(&buf, size)) return false; } case NT_MSG_RPC_RESPONSE: { @@ -205,7 +189,8 @@ MessageReader::Run() if (!Read16(&uid)) return false; unsigned long size; if (!ReadULEB128(&size)) return false; - if (!Read(size)) return false; + char *buf; + if (!Read(&buf, size)) return false; } default: m_error = "unrecognized message type"; @@ -213,138 +198,3 @@ MessageReader::Run() } return true; } - -bool -MessageReader::ReadType(NT_Type *type) -{ - if (!Read(1)) return false; - size_t len = NT_ReadType(m_buf, type, m_proto_rev); - if (len == 0) - { - m_error = "unrecognized value type"; - return false; - } - return true; -} - -bool -MessageReader::ReadValue(NT_Type type, NT_Value *value) -{ - value->type = type; - value->last_change = 0; - switch (type) - { - case NT_BOOLEAN: - { - unsigned int v; - if (!Read8(&v)) return false; - value->data.v_boolean = v ? 1 : 0; - break; - } - case NT_DOUBLE: - { - if (!Read(8)) return false; - char *buf = m_buf; - value->data.v_double = ReadDouble(buf); - break; - } - case NT_STRING: - if (!ReadString(&value->data.v_string)) return false; - break; - case NT_RAW: - case NT_RPC: - if (m_proto_rev < 0x0300u) - { - m_error = "received raw or RPC value in protocol < 3.0"; - return false; - } - if (!ReadString(&value->data.v_raw)) return false; - break; - case NT_BOOLEAN_ARRAY: - { - // size - unsigned int size; - if (!Read8(&size)) return false; - value->data.arr_boolean.size = size; - - // array values - if (!Read(size)) return false; - value->data.arr_boolean.arr = (int *)std::malloc(size * sizeof(int)); - for (unsigned int i=0; idata.arr_boolean.arr[i] = m_buf[i] ? 1 : 0; - break; - } - case NT_DOUBLE_ARRAY: - { - // size - unsigned int size; - if (!Read8(&size)) return false; - value->data.arr_double.size = size; - - // array values - if (!Read(size*8)) return false; - value->data.arr_double.arr = - (double *)std::malloc(size * sizeof(double)); - char *buf = m_buf; - for (unsigned int i=0; idata.arr_double.arr[i] = ReadDouble(buf); - break; - } - case NT_STRING_ARRAY: - { - // size - unsigned int size; - if (!Read8(&size)) return false; - value->data.arr_string.size = size; - - // array values - if (!Read(size*8)) return false; - value->data.arr_string.arr = - (NT_String *)std::malloc(size * sizeof(NT_String)); - for (unsigned int i=0; idata.arr_string.arr[i])) - { - // cleanup to avoid memory leaks - for (unsigned int j=0; jdata.arr_string.arr[j].str); - } - std::free(value->data.arr_string.arr); - return false; - } - } - break; - } - default: - m_error = "invalid type when trying to read value"; - return false; - } - return true; -} - -bool -MessageReader::ReadString(NT_String *str) -{ - if (m_proto_rev < 0x0300u) - { - unsigned int v; - if (!Read16(&v)) return false; - str->len = v; - } - else - { - unsigned long v; - if (!ReadULEB128(&v)) return false; - str->len = v; - } - str->str = (char *)std::malloc(str->len + 1); - if (!m_is.read(str->str, str->len)) - { - std::free(str->str); - str->str = 0; - return false; - } - str->str[str->len] = '\0'; - return true; -} diff --git a/src/nt_messagereader.h b/src/nt_messagereader.h index 98ddf8ec06..bac60957b9 100644 --- a/src/nt_messagereader.h +++ b/src/nt_messagereader.h @@ -8,12 +8,7 @@ #ifndef NT_MESSAGEREADER_H_ #define NT_MESSAGEREADER_H_ -#include - -#include "ntcore.h" -#include "nt_leb128.h" -#include "nt_raw_istream.h" -#include "nt_encoding.h" +#include "nt_wiredecoder.h" namespace NtImpl { @@ -22,9 +17,8 @@ class MessageHandler void anchor(); public: + // Needed for protocol rev 2.0 ENTRY_UPDATE messages. virtual NT_Type GetEntryType(unsigned int id) = 0; - virtual size_t GetRpcParamTypes(NT_Type *types, unsigned int id) = 0; - virtual size_t GetRpcResultTypes(NT_Type *types, unsigned int id) = 0; // All of these functions are expected to take ownership of passed // strings/values. @@ -50,19 +44,17 @@ public: virtual void GotClearEntries() = 0; virtual void GotExecuteRpc(unsigned int id, unsigned int uid, - NT_Value *params_start, - NT_Value *params_end) = 0; + const char *params) = 0; virtual void GotRpcResponse(unsigned int id, unsigned int uid, - NT_Value *results_start, - NT_Value *results_end) = 0; + const char *results) = 0; private: MessageHandler(const MessageHandler&); MessageHandler& operator= (const MessageHandler&); }; -class MessageReader +class MessageReader : private WireDecoder { public: explicit MessageReader(MessageHandler &handler, @@ -72,76 +64,26 @@ public: void SetProtocolRev(unsigned int proto_rev) { - m_proto_rev = proto_rev; + WireDecoder::SetProtocolRev(proto_rev); } bool Run(); void Reset() { - m_error = 0; + WireDecoder::Reset(); } const char *GetError() const { - return m_error; + return WireDecoder::GetError(); } -protected: - bool Read(std::size_t len) - { - if (len > m_allocated) - Realloc(len); - return m_is.read(m_buf, len); - } - - bool Read8(unsigned int *val) - { - if (!Read(1)) return false; - char *buf = m_buf; - *val = NtImpl::Read8(buf); - return true; - } - - bool Read16(unsigned int *val) - { - if (!Read(2)) return false; - char *buf = m_buf; - *val = NtImpl::Read16(buf); - return true; - } - - bool Read32(unsigned long *val) - { - if (!Read(4)) return false; - char *buf = m_buf; - *val = NtImpl::Read32(buf); - return true; - } - - bool ReadULEB128(unsigned long *val) - { - return read_uleb128(m_is, val); - } - - bool ReadType(NT_Type *type); - bool ReadValue(NT_Type type, NT_Value *value); - bool ReadString(NT_String *str); - private: MessageReader(const MessageReader&); MessageReader& operator= (const MessageReader&); - void Realloc(std::size_t len); - MessageHandler &m_handler; - raw_istream &m_is; - - char *m_buf; - std::size_t m_allocated; - - unsigned int m_proto_rev; - const char *m_error; NT_Type m_rpc_types[256]; }; diff --git a/src/nt_wiredecoder.cpp b/src/nt_wiredecoder.cpp new file mode 100644 index 0000000000..730e5f7b1d --- /dev/null +++ b/src/nt_wiredecoder.cpp @@ -0,0 +1,186 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "nt_wiredecoder.h" + +#include +#include +#include +#include + +#include "nt_internal.h" +#include "nt_leb128.h" + +using namespace NtImpl; + +WireDecoder::WireDecoder(raw_istream& is, unsigned int proto_rev) + : m_is(is) +{ + m_allocated = 1024; + m_buf = (char *)std::malloc(m_allocated); + m_proto_rev = proto_rev; + m_error = 0; +} + +WireDecoder::~WireDecoder() +{ + std::free(m_buf); +} + +void +WireDecoder::Realloc(std::size_t len) +{ + if (m_allocated >= len) + return; + std::size_t newlen = m_allocated * 2; + while (newlen < len) + newlen *= 2; + m_buf = (char *)std::realloc(m_buf, newlen); + m_allocated = newlen; +} + +bool +WireDecoder::ReadType(NT_Type *type) +{ + unsigned int itype; + if (!Read8(&itype)) return false; + switch (itype) + { + case 0x00: *type = NT_BOOLEAN; break; + case 0x01: *type = NT_DOUBLE; break; + case 0x02: *type = NT_STRING; break; + case 0x03: *type = NT_RAW; break; + case 0x10: *type = NT_BOOLEAN_ARRAY; break; + case 0x11: *type = NT_DOUBLE_ARRAY; break; + case 0x12: *type = NT_STRING_ARRAY; break; + case 0x20: *type = NT_RPC; break; + default: + m_error = "unrecognized value type"; + return false; + } + return true; +} + +bool +WireDecoder::ReadValue(NT_Type type, NT_Value *value) +{ + value->type = type; + value->last_change = 0; + switch (type) + { + case NT_BOOLEAN: + { + unsigned int v; + if (!Read8(&v)) return false; + value->data.v_boolean = v ? 1 : 0; + break; + } + case NT_DOUBLE: + { + if (!ReadDouble(&value->data.v_double)) return false; + break; + } + case NT_STRING: + if (!ReadString(&value->data.v_string)) return false; + break; + case NT_RAW: + case NT_RPC: + if (m_proto_rev < 0x0300u) + { + m_error = "received raw or RPC value in protocol < 3.0"; + return false; + } + if (!ReadString(&value->data.v_raw)) return false; + break; + case NT_BOOLEAN_ARRAY: + { + // size + unsigned int size; + if (!Read8(&size)) return false; + value->data.arr_boolean.size = size; + + // array values + char *buf; + if (!Read(&buf, size)) return false; + value->data.arr_boolean.arr = (int *)std::malloc(size * sizeof(int)); + for (unsigned int i=0; idata.arr_boolean.arr[i] = buf[i] ? 1 : 0; + break; + } + case NT_DOUBLE_ARRAY: + { + // size + unsigned int size; + if (!Read8(&size)) return false; + value->data.arr_double.size = size; + + // array values + char *buf; + if (!Read(&buf, size*8)) return false; + value->data.arr_double.arr = + (double *)std::malloc(size * sizeof(double)); + for (unsigned int i=0; idata.arr_double.arr[i] = NtImpl::ReadDouble(buf); + break; + } + case NT_STRING_ARRAY: + { + // size + unsigned int size; + if (!Read8(&size)) return false; + value->data.arr_string.size = size; + + // array values + value->data.arr_string.arr = + (NT_String *)std::malloc(size * sizeof(NT_String)); + for (unsigned int i=0; idata.arr_string.arr[i])) + { + // cleanup to avoid memory leaks + for (unsigned int j=0; jdata.arr_string.arr[j].str); + } + std::free(value->data.arr_string.arr); + return false; + } + } + break; + } + default: + m_error = "invalid type when trying to read value"; + return false; + } + return true; +} + +bool +WireDecoder::ReadString(NT_String *str) +{ + if (m_proto_rev < 0x0300u) + { + unsigned int v; + if (!Read16(&v)) return false; + str->len = v; + } + else + { + unsigned long v; + if (!ReadULEB128(&v)) return false; + str->len = v; + } + str->str = (char *)std::malloc(str->len + 1); + if (!m_is.read(str->str, str->len)) + { + std::free(str->str); + str->str = 0; + return false; + } + str->str[str->len] = '\0'; + return true; +} diff --git a/src/nt_wiredecoder.h b/src/nt_wiredecoder.h new file mode 100644 index 0000000000..751cf2ddff --- /dev/null +++ b/src/nt_wiredecoder.h @@ -0,0 +1,108 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef NT_WIREDECODER_H_ +#define NT_WIREDECODER_H_ + +#include + +#include "ntcore.h" +#include "nt_leb128.h" +#include "nt_raw_istream.h" +#include "nt_encoding.h" + +namespace NtImpl { + +class WireDecoder +{ +public: + explicit WireDecoder(raw_istream& is, unsigned int proto_rev); + ~WireDecoder(); + + void SetProtocolRev(unsigned int proto_rev) + { + m_proto_rev = proto_rev; + } + + void Reset() + { + m_error = 0; + } + + const char *GetError() const + { + return m_error; + } + + bool Read(char **buf, std::size_t len) + { + if (len > m_allocated) + Realloc(len); + *buf = m_buf; + return m_is.read(m_buf, len); + } + + bool Read8(unsigned int *val) + { + char *buf; + if (!Read(&buf, 1)) return false; + *val = NtImpl::Read8(buf); + return true; + } + + bool Read16(unsigned int *val) + { + char *buf; + if (!Read(&buf, 2)) return false; + *val = NtImpl::Read16(buf); + return true; + } + + bool Read32(unsigned long *val) + { + char *buf; + if (!Read(&buf, 4)) return false; + *val = NtImpl::Read32(buf); + return true; + } + + bool ReadDouble(double *val) + { + char *buf; + if (!Read(&buf, 8)) return false; + *val = NtImpl::ReadDouble(buf); + return true; + } + + bool ReadULEB128(unsigned long *val) + { + return read_uleb128(m_is, val); + } + + bool ReadType(NT_Type *type); + bool ReadValue(NT_Type type, NT_Value *value); + bool ReadString(NT_String *str); + +protected: + unsigned int m_proto_rev; + const char *m_error; + +private: + WireDecoder(const WireDecoder&); + WireDecoder& operator= (const WireDecoder&); + + void Realloc(std::size_t len); + + raw_istream &m_is; + + char *m_buf; + std::size_t m_allocated; +}; + +} // namespace NtImpl + +#endif /* NT_WIREDECODER_H_ */