Squashed 'third_party/ntcore_2016/' content from commit d8de5e4
Change-Id: Id4839f41b6a620d8bae58dcf1710016671cc4992
git-subtree-dir: third_party/ntcore_2016
git-subtree-split: d8de5e4f19e612e7102172c0dbf152ce82d3d63a
diff --git a/src/WireDecoder.cpp b/src/WireDecoder.cpp
new file mode 100644
index 0000000..138225e
--- /dev/null
+++ b/src/WireDecoder.cpp
@@ -0,0 +1,206 @@
+/*----------------------------------------------------------------------------*/
+/* 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 "WireDecoder.h"
+
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+
+#include "llvm/MathExtras.h"
+#include "leb128.h"
+
+using namespace nt;
+
+static double ReadDouble(const char*& buf) {
+ // Fast but non-portable!
+ std::uint64_t val = (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ val <<= 8;
+ val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ val <<= 8;
+ val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ val <<= 8;
+ val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ val <<= 8;
+ val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ val <<= 8;
+ val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ val <<= 8;
+ val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ val <<= 8;
+ val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
+ ++buf;
+ return llvm::BitsToDouble(val);
+}
+
+WireDecoder::WireDecoder(raw_istream& is, unsigned int proto_rev) : m_is(is) {
+ // Start with a 1K temporary buffer. Use malloc instead of new so we can
+ // realloc.
+ m_allocated = 1024;
+ m_buf = static_cast<char*>(std::malloc(m_allocated));
+ m_proto_rev = proto_rev;
+ m_error = nullptr;
+}
+
+WireDecoder::~WireDecoder() { std::free(m_buf); }
+
+bool WireDecoder::ReadDouble(double* val) {
+ const char* buf;
+ if (!Read(&buf, 8)) return false;
+ *val = ::ReadDouble(buf);
+ return true;
+}
+
+void WireDecoder::Realloc(std::size_t len) {
+ // Double current buffer size until we have enough space.
+ if (m_allocated >= len) return;
+ std::size_t newlen = m_allocated * 2;
+ while (newlen < len) newlen *= 2;
+ m_buf = static_cast<char*>(std::realloc(m_buf, newlen));
+ m_allocated = newlen;
+}
+
+bool WireDecoder::ReadType(NT_Type* type) {
+ unsigned int itype;
+ if (!Read8(&itype)) return false;
+ // Convert from byte value to enum
+ 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:
+ *type = NT_UNASSIGNED;
+ m_error = "unrecognized value type";
+ return false;
+ }
+ return true;
+}
+
+std::shared_ptr<Value> WireDecoder::ReadValue(NT_Type type) {
+ switch (type) {
+ case NT_BOOLEAN: {
+ unsigned int v;
+ if (!Read8(&v)) return nullptr;
+ return Value::MakeBoolean(v != 0);
+ }
+ case NT_DOUBLE: {
+ double v;
+ if (!ReadDouble(&v)) return nullptr;
+ return Value::MakeDouble(v);
+ }
+ case NT_STRING: {
+ std::string v;
+ if (!ReadString(&v)) return nullptr;
+ return Value::MakeString(std::move(v));
+ }
+ case NT_RAW: {
+ if (m_proto_rev < 0x0300u) {
+ m_error = "received raw value in protocol < 3.0";
+ return nullptr;
+ }
+ std::string v;
+ if (!ReadString(&v)) return nullptr;
+ return Value::MakeRaw(std::move(v));
+ }
+ case NT_RPC: {
+ if (m_proto_rev < 0x0300u) {
+ m_error = "received RPC value in protocol < 3.0";
+ return nullptr;
+ }
+ std::string v;
+ if (!ReadString(&v)) return nullptr;
+ return Value::MakeRpc(std::move(v));
+ }
+ case NT_BOOLEAN_ARRAY: {
+ // size
+ unsigned int size;
+ if (!Read8(&size)) return nullptr;
+
+ // array values
+ const char* buf;
+ if (!Read(&buf, size)) return nullptr;
+ std::vector<int> v(size);
+ for (unsigned int i = 0; i < size; ++i)
+ v[i] = buf[i] ? 1 : 0;
+ return Value::MakeBooleanArray(std::move(v));
+ }
+ case NT_DOUBLE_ARRAY: {
+ // size
+ unsigned int size;
+ if (!Read8(&size)) return nullptr;
+
+ // array values
+ const char* buf;
+ if (!Read(&buf, size * 8)) return nullptr;
+ std::vector<double> v(size);
+ for (unsigned int i = 0; i < size; ++i)
+ v[i] = ::ReadDouble(buf);
+ return Value::MakeDoubleArray(std::move(v));
+ }
+ case NT_STRING_ARRAY: {
+ // size
+ unsigned int size;
+ if (!Read8(&size)) return nullptr;
+
+ // array values
+ std::vector<std::string> v(size);
+ for (unsigned int i = 0; i < size; ++i) {
+ if (!ReadString(&v[i])) return nullptr;
+ }
+ return Value::MakeStringArray(std::move(v));
+ }
+ default:
+ m_error = "invalid type when trying to read value";
+ return nullptr;
+ }
+}
+
+bool WireDecoder::ReadString(std::string* str) {
+ size_t len;
+ if (m_proto_rev < 0x0300u) {
+ unsigned int v;
+ if (!Read16(&v)) return false;
+ len = v;
+ } else {
+ unsigned long v;
+ if (!ReadUleb128(&v)) return false;
+ len = v;
+ }
+ const char* buf;
+ if (!Read(&buf, len)) return false;
+ *str = llvm::StringRef(buf, len);
+ return true;
+}