diff --git a/include/ntcore.h b/include/ntcore.h index 28acc68354..6cf8b81619 100644 --- a/include/ntcore.h +++ b/include/ntcore.h @@ -312,20 +312,6 @@ void NT_InitString(struct NT_String *str); void NT_DisposeConnectionInfoArray(struct NT_ConnectionInfo *arr, size_t count); -/* - * Message Encoding Functions - */ -size_t NT_WriteType(char *buf, enum NT_Type type, unsigned int proto_rev); -size_t NT_ReadType(const char *buf, enum NT_Type *type, unsigned int proto_rev); - -size_t NT_GetStringSize(const struct NT_String *value, unsigned int proto_rev); -size_t NT_WriteString(char *buf, const struct NT_String *str, - unsigned int proto_rev); - -size_t NT_GetValueSize(const struct NT_Value *value, unsigned int proto_rev); -size_t NT_WriteValue(char *buf, const struct NT_Value *value, - unsigned int proto_rev); - #ifdef __cplusplus } #endif diff --git a/src/nt_encoding.cpp b/src/nt_encoding.cpp deleted file mode 100644 index 60603e5aa0..0000000000 --- a/src/nt_encoding.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/*----------------------------------------------------------------------------*/ -/* 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_encoding.h" -#include "ntcore.h" - -#include -#include - -#include "nt_leb128.h" - -using namespace NtImpl; - -void -NtImpl::WriteDouble(char* &buf, double val) -{ - std::uint64_t v = *reinterpret_cast(&val); - *buf++ = (char)((v >> 56) & 0xff); - *buf++ = (char)((v >> 48) & 0xff); - *buf++ = (char)((v >> 40) & 0xff); - *buf++ = (char)((v >> 32) & 0xff); - *buf++ = (char)((v >> 24) & 0xff); - *buf++ = (char)((v >> 16) & 0xff); - *buf++ = (char)((v >> 8) & 0xff); - *buf++ = (char)(v & 0xff); -} - -size_t -NT_WriteType(char *buf, NT_Type type, unsigned int proto_rev) -{ - switch (type) - { - case NT_BOOLEAN: *buf = 0x00; break; - case NT_DOUBLE: *buf = 0x01; break; - case NT_STRING: *buf = 0x02; break; - case NT_RAW: - if (proto_rev < 0x0300u) - return 0; - *buf = 0x03; - break; - case NT_BOOLEAN_ARRAY: *buf = 0x10; break; - case NT_DOUBLE_ARRAY: *buf = 0x11; break; - case NT_STRING_ARRAY: *buf = 0x12; break; - case NT_RPC: - if (proto_rev < 0x0300u) - return 0; - *buf = 0x20; - break; - default: - return 0; - } - return 1; -} - -size_t -NT_ReadType(const char *buf, NT_Type *type, unsigned int proto_rev) -{ - switch (buf[0]) - { - 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: return 0; - } - return 1; -} - -size_t -NT_GetStringSize(const NT_String *str, unsigned int proto_rev) -{ - if (proto_rev < 0x0300u) - return 2 + str->len; - return size_uleb128(str->len) + str->len; -} - -size_t -NT_WriteString(char *buf, const NT_String *str, unsigned int proto_rev) -{ - char *start = buf; - if (proto_rev < 0x0300u) - Write16(buf, str->len); - else - buf += write_uleb128(buf, str->len); - std::memcpy(buf, str->str, str->len); - return (buf - start) + str->len; -} - -size_t -NT_GetValueSize(const NT_Value *value, unsigned int proto_rev) -{ - switch (value->type) - { - case NT_BOOLEAN: - return 1; - case NT_DOUBLE: - return 8; - case NT_STRING: - return NT_GetStringSize(&value->data.v_string, proto_rev); - case NT_RAW: - case NT_RPC: - if (proto_rev < 0x0300u) - return 0; - return NT_GetStringSize(&value->data.v_raw, proto_rev); - case NT_BOOLEAN_ARRAY: - return 1 + value->data.arr_boolean.size; - case NT_DOUBLE_ARRAY: - return 1 + value->data.arr_double.size * 8; - case NT_STRING_ARRAY: - { - size_t len = 1; - for (size_t i=0; idata.arr_string.size; ++i) - len += NT_GetStringSize(&value->data.arr_string.arr[i], proto_rev); - return len; - } - default: - return 0; - } - return 1; -} - -size_t -NT_WriteValue(char *buf, const NT_Value *value, unsigned int proto_rev) -{ - char *start = buf; - switch (value->type) - { - case NT_BOOLEAN: - Write8(buf, value->data.v_boolean ? 1 : 0); - break; - case NT_DOUBLE: - WriteDouble(buf, value->data.v_double); - break; - case NT_STRING: - buf += NT_WriteString(buf, &value->data.v_string, proto_rev); - break; - case NT_RAW: - case NT_RPC: - if (proto_rev < 0x0300u) - return 0; - buf += NT_WriteString(buf, &value->data.v_raw, proto_rev); - break; - case NT_BOOLEAN_ARRAY: - Write8(buf, value->data.arr_boolean.size); - for (size_t i=0; idata.arr_boolean.size; ++i) - Write8(buf, value->data.arr_boolean.arr[i] ? 1 : 0); - break; - case NT_DOUBLE_ARRAY: - Write8(buf, value->data.arr_double.size); - for (size_t i=0; idata.arr_double.size; ++i) - WriteDouble(buf, value->data.arr_double.arr[i] ? 1 : 0); - break; - case NT_STRING_ARRAY: - Write8(buf, value->data.arr_string.size); - for (size_t i=0; idata.arr_string.size; ++i) - buf += NT_WriteString(buf, &value->data.arr_string.arr[i], - proto_rev); - break; - default: - return 0; - } - return buf - start; -} diff --git a/src/nt_encoding.h b/src/nt_encoding.h deleted file mode 100644 index ff40f40090..0000000000 --- a/src/nt_encoding.h +++ /dev/null @@ -1,39 +0,0 @@ -/*----------------------------------------------------------------------------*/ -/* 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_UTIL_H_ -#define NT_UTIL_H_ - -namespace NtImpl { - -inline void -Write8(char* &buf, unsigned int val) -{ - *buf++ = (char)(val & 0xff); -} - -inline void -Write16(char* &buf, unsigned int val) -{ - *buf++ = (char)((val >> 8) & 0xff); - *buf++ = (char)(val & 0xff); -} - -inline void -Write32(char* &buf, unsigned long val) -{ - *buf++ = (char)((val >> 24) & 0xff); - *buf++ = (char)((val >> 16) & 0xff); - *buf++ = (char)((val >> 8) & 0xff); - *buf++ = (char)(val & 0xff); -} - -void WriteDouble(char* &buf, double val); - -} // namespace NtImpl - -#endif /* NT_UTIL_H */ diff --git a/src/nt_messagewriter.cpp b/src/nt_messagewriter.cpp index 0be8908be4..62eb50332d 100644 --- a/src/nt_messagewriter.cpp +++ b/src/nt_messagewriter.cpp @@ -7,53 +7,25 @@ #include "nt_messagewriter.h" -#include -#include - #include "nt_internal.h" -#include "nt_leb128.h" using namespace NtImpl; -MessageWriter::MessageWriter(unsigned int proto_rev) -{ - m_start = m_cur = (char *)std::malloc(1024); - m_end = m_start + 1024; - m_proto_rev = proto_rev; - m_error = 0; -} - MessageWriter::~MessageWriter() { - std::free(m_start); -} - -void -MessageWriter::EnsureSlow(std::size_t len) -{ - assert(m_end > m_cur); - if (static_cast(m_end - m_cur) >= len) - return; - std::size_t pos = m_cur - m_start; - std::size_t newlen = (m_end - m_start) * 2; - while (newlen < (pos + len)) - newlen *= 2; - m_start = (char *)std::realloc(m_start, newlen); - m_cur = m_start + pos; - m_end = m_start + newlen; } void MessageWriter::WriteKeepAlive() { - Ensure(1); + Reserve(1); Write8(NT_MSG_KEEP_ALIVE); } void MessageWriter::WriteClientHello(const NT_String &self_id) { - Ensure(3); + Reserve(3); Write8(NT_MSG_CLIENT_HELLO); Write16(m_proto_rev); if (m_proto_rev < 0x0300u) @@ -64,7 +36,7 @@ MessageWriter::WriteClientHello(const NT_String &self_id) void MessageWriter::WriteProtoUnsup() { - Ensure(3); + Reserve(3); Write8(NT_MSG_PROTO_UNSUP); Write16(m_proto_rev); } @@ -72,7 +44,7 @@ MessageWriter::WriteProtoUnsup() void MessageWriter::WriteServerHelloDone() { - Ensure(1); + Reserve(1); Write8(NT_MSG_SERVER_HELLO_DONE); } @@ -81,7 +53,7 @@ MessageWriter::WriteServerHello(unsigned int flags, const NT_String &self_id) { if (m_proto_rev < 0x0300u) return; // new message in version 3.0 - Ensure(2); + Reserve(2); Write8(NT_MSG_SERVER_HELLO); Write8(flags); WriteString(self_id); @@ -92,7 +64,7 @@ MessageWriter::WriteClientHelloDone() { if (m_proto_rev < 0x0300u) return; // new message in version 3.0 - Ensure(1); + Reserve(1); Write8(NT_MSG_CLIENT_HELLO_DONE); } @@ -103,10 +75,10 @@ MessageWriter::WriteEntryAssign(const NT_String &name, const NT_Value &value, unsigned int flags) { - Ensure(1); + Reserve(1); Write8(NT_MSG_ENTRY_ASSIGN); WriteString(name); - Ensure(6); + Reserve(6); WriteType(value.type); Write16(id); Write16(seq_num); @@ -120,7 +92,7 @@ MessageWriter::WriteEntryUpdate(unsigned int id, unsigned int seq_num, const NT_Value &value) { - Ensure(6); + Reserve(6); Write8(NT_MSG_ENTRY_UPDATE); Write16(id); Write16(seq_num); @@ -134,7 +106,7 @@ MessageWriter::WriteFlagsUpdate(unsigned int id, unsigned int flags) { if (m_proto_rev < 0x0300u) return; // new message in version 3.0 - Ensure(4); + Reserve(4); Write8(NT_MSG_FLAGS_UPDATE); Write16(id); Write8(flags); @@ -145,7 +117,7 @@ MessageWriter::WriteEntryDelete(unsigned int id) { if (m_proto_rev < 0x0300u) return; // new message in version 3.0 - Ensure(3); + Reserve(3); Write8(NT_MSG_ENTRY_DELETE); Write16(id); } @@ -156,7 +128,7 @@ MessageWriter::WriteClearEntries() if (m_proto_rev < 0x0300u) return; // new message in version 3.0 - Ensure(5); + Reserve(5); Write8(NT_MSG_CLEAR_ENTRIES); Write32(NT_CLEAR_ALL_MAGIC); } @@ -189,59 +161,16 @@ MessageWriter::WriteRpc(unsigned int msg_type, if (m_proto_rev < 0x0300u) return; // new message in version 3.0 - Ensure(5); + Reserve(5); Write8(msg_type); Write16(id); Write16(uid); unsigned long len = 0; for (const NT_Value *value = values_start; value != values_end; ++value) - len += NT_GetValueSize(value, m_proto_rev); + len += GetValueSize(*value); WriteULEB128(len); for (const NT_Value *value = values_start; value != values_end; ++value) WriteValue(*value); } - -void -MessageWriter::WriteULEB128(unsigned long val) -{ - Ensure(size_uleb128(val)); - m_cur += write_uleb128(m_cur, val); -} - -void -MessageWriter::WriteType(NT_Type type) -{ - Ensure(1); - size_t len = NT_WriteType(m_cur, type, m_proto_rev); - if (len == 0) - m_error = "unrecognized type"; - m_cur += len; -} - -void -MessageWriter::WriteValue(const NT_Value &value) -{ - std::size_t len = NT_GetValueSize(&value, m_proto_rev); - if (len == 0) - { - m_error = "unrecognized type when writing value"; - return; - } - Ensure(len); - m_cur += NT_WriteValue(m_cur, &value, m_proto_rev); -} - -void -MessageWriter::WriteString(const NT_String &str) -{ - std::size_t len = NT_GetStringSize(&str, m_proto_rev); - if (len == 0) - { - m_error = "invalid string"; - return; - } - Ensure(len); - m_cur += NT_WriteString(m_cur, &str, m_proto_rev); -} diff --git a/src/nt_messagewriter.h b/src/nt_messagewriter.h index 64b22cc7f9..79a9bec7d4 100644 --- a/src/nt_messagewriter.h +++ b/src/nt_messagewriter.h @@ -8,44 +8,39 @@ #ifndef NT_MESSAGEWRITER_H_ #define NT_MESSAGEWRITER_H_ -#include -#include - -#include "ntcore.h" -#include "nt_encoding.h" +#include "nt_wireencoder.h" namespace NtImpl { -class MessageWriter +class MessageWriter : private WireEncoder { public: - explicit MessageWriter(unsigned int proto_rev); + explicit MessageWriter(unsigned int proto_rev) : WireEncoder(proto_rev) {} ~MessageWriter(); void SetProtocolRev(unsigned int proto_rev) { - m_proto_rev = proto_rev; + WireEncoder::SetProtocolRev(proto_rev); } void Reset() { - m_cur = m_start; - m_error = 0; + WireEncoder::Reset(); } const char *GetError() const { - return m_error; + return WireEncoder::GetError(); } const char *GetData() const { - return m_start; + return WireEncoder::GetData(); } std::size_t GetSize() const { - return m_cur - m_start; + return WireEncoder::GetSize(); } void WriteKeepAlive(); @@ -74,50 +69,15 @@ public: const NT_Value *results_start, const NT_Value *results_end); -protected: - void Ensure(std::size_t len) - { - assert(m_end > m_cur); - if (static_cast(m_end - m_cur) < len) - EnsureSlow(len); - } - - void Write8(unsigned int val) - { - NtImpl::Write8(m_cur, val); - } - - void Write16(unsigned int val) - { - NtImpl::Write16(m_cur, val); - } - - void Write32(unsigned long val) - { - NtImpl::Write32(m_cur, val); - } - - void WriteULEB128(unsigned long val); - void WriteType(NT_Type type); - void WriteValue(const NT_Value &value); - void WriteString(const NT_String &str); - private: MessageWriter(const MessageWriter&); MessageWriter& operator= (const MessageWriter&); - void EnsureSlow(std::size_t len); void WriteRpc(unsigned int msg_type, unsigned int id, unsigned int uid, const NT_Value *values_start, const NT_Value *values_end); - - char *m_start; - char *m_cur; - char *m_end; - unsigned int m_proto_rev; - const char *m_error; }; } // namespace NtImpl diff --git a/src/nt_wireencoder.cpp b/src/nt_wireencoder.cpp new file mode 100644 index 0000000000..8b5501f673 --- /dev/null +++ b/src/nt_wireencoder.cpp @@ -0,0 +1,228 @@ +/*----------------------------------------------------------------------------*/ +/* 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_wireencoder.h" + +#include +#include +#include +#include + +#include "nt_internal.h" +#include "nt_leb128.h" + +using namespace NtImpl; + +WireEncoder::WireEncoder(unsigned int proto_rev) +{ + m_start = m_cur = (char *)std::malloc(1024); + m_end = m_start + 1024; + m_proto_rev = proto_rev; + m_error = 0; +} + +WireEncoder::~WireEncoder() +{ + std::free(m_start); +} + +void +WireEncoder::WriteDouble(double val) +{ + Reserve(8); + std::uint64_t v = *reinterpret_cast(&val); + *m_cur++ = (char)((v >> 56) & 0xff); + *m_cur++ = (char)((v >> 48) & 0xff); + *m_cur++ = (char)((v >> 40) & 0xff); + *m_cur++ = (char)((v >> 32) & 0xff); + *m_cur++ = (char)((v >> 24) & 0xff); + *m_cur++ = (char)((v >> 16) & 0xff); + *m_cur++ = (char)((v >> 8) & 0xff); + *m_cur++ = (char)(v & 0xff); +} + +void +WireEncoder::ReserveSlow(std::size_t len) +{ + assert(m_end > m_cur); + if (static_cast(m_end - m_cur) >= len) + return; + std::size_t pos = m_cur - m_start; + std::size_t newlen = (m_end - m_start) * 2; + while (newlen < (pos + len)) + newlen *= 2; + m_start = (char *)std::realloc(m_start, newlen); + m_cur = m_start + pos; + m_end = m_start + newlen; +} + +void +WireEncoder::WriteULEB128(unsigned long val) +{ + Reserve(size_uleb128(val)); + m_cur += write_uleb128(m_cur, val); +} + +void +WireEncoder::WriteType(NT_Type type) +{ + Reserve(1); + switch (type) + { + case NT_BOOLEAN: *m_cur = 0x00; break; + case NT_DOUBLE: *m_cur = 0x01; break; + case NT_STRING: *m_cur = 0x02; break; + case NT_RAW: + if (m_proto_rev < 0x0300u) + { + m_error = "raw type not supported in protocol < 3.0"; + return; + } + *m_cur = 0x03; + break; + case NT_BOOLEAN_ARRAY: *m_cur = 0x10; break; + case NT_DOUBLE_ARRAY: *m_cur = 0x11; break; + case NT_STRING_ARRAY: *m_cur = 0x12; break; + case NT_RPC: + if (m_proto_rev < 0x0300u) + { + m_error = "RPC type not supported in protocol < 3.0"; + return; + } + *m_cur = 0x20; + break; + default: + m_error = "unrecognized type"; + return; + } + ++m_cur; +} + +std::size_t +WireEncoder::GetValueSize(const NT_Value &value) +{ + switch (value.type) + { + case NT_BOOLEAN: + return 1; + case NT_DOUBLE: + return 8; + case NT_STRING: + return GetStringSize(value.data.v_string); + case NT_RAW: + case NT_RPC: + if (m_proto_rev < 0x0300u) + return 0; + return GetStringSize(value.data.v_raw); + case NT_BOOLEAN_ARRAY: + return 1 + value.data.arr_boolean.size; + case NT_DOUBLE_ARRAY: + return 1 + value.data.arr_double.size * 8; + case NT_STRING_ARRAY: + { + size_t len = 1; + for (size_t i=0; i 0xff) + size = 0xff; + Reserve(1+size); + Write8(size); + + for (std::size_t i=0; i 0xff) + size = 0xff; + Reserve(1+size*8); + Write8(size); + + for (std::size_t i=0; i 0xff) + size = 0xff; + Write8(size); + + for (std::size_t i=0; i 0xffff) + len = 0xffff; + Write16(len); + } + else + WriteULEB128(len); + + // contents + Reserve(len); + std::memcpy(m_cur, str.str, len); + m_cur += len; +} diff --git a/src/nt_wireencoder.h b/src/nt_wireencoder.h new file mode 100644 index 0000000000..4f03e0352b --- /dev/null +++ b/src/nt_wireencoder.h @@ -0,0 +1,106 @@ +/*----------------------------------------------------------------------------*/ +/* 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_WIREENCODER_H_ +#define NT_WIREENCODER_H_ + +#include +#include + +#include "ntcore.h" + +namespace NtImpl { + +class WireEncoder +{ +public: + explicit WireEncoder(unsigned int proto_rev); + ~WireEncoder(); + + void SetProtocolRev(unsigned int proto_rev) + { + m_proto_rev = proto_rev; + } + + void Reset() + { + m_cur = m_start; + m_error = 0; + } + + const char *GetError() const + { + return m_error; + } + + const char *GetData() const + { + return m_start; + } + + std::size_t GetSize() const + { + return m_cur - m_start; + } + + void Reserve(std::size_t len) + { + //assert(m_end > m_cur); + if (static_cast(m_end - m_cur) < len) + ReserveSlow(len); + } + + void Write8(unsigned int val) + { + Reserve(1); + *m_cur++ = (char)(val & 0xff); + } + + void Write16(unsigned int val) + { + Reserve(2); + *m_cur++ = (char)((val >> 8) & 0xff); + *m_cur++ = (char)(val & 0xff); + } + + void Write32(unsigned long val) + { + Reserve(4); + *m_cur++ = (char)((val >> 24) & 0xff); + *m_cur++ = (char)((val >> 16) & 0xff); + *m_cur++ = (char)((val >> 8) & 0xff); + *m_cur++ = (char)(val & 0xff); + } + + void WriteDouble(double val); + + void WriteULEB128(unsigned long val); + void WriteType(NT_Type type); + void WriteValue(const NT_Value &value); + void WriteString(const NT_String &str); + + std::size_t GetValueSize(const NT_Value &value); + std::size_t GetStringSize(const NT_String &str); + +protected: + unsigned int m_proto_rev; + const char *m_error; + +private: + WireEncoder(const WireEncoder&); + WireEncoder& operator= (const WireEncoder&); + + void ReserveSlow(std::size_t len); + + char *m_start; + char *m_cur; + char *m_end; +}; + +} // namespace NtImpl + +#endif /* NT_WIREENCODER_H_ */