blob: 138225e2d77a7f34c9ff66970748359b5b1c69ea [file] [log] [blame]
Brian Silvermanf7bd1c22015-12-24 16:07:11 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2015. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "WireDecoder.h"
9
10#include <cassert>
11#include <cstdint>
12#include <cstdlib>
13#include <cstring>
14
15#include "llvm/MathExtras.h"
16#include "leb128.h"
17
18using namespace nt;
19
20static double ReadDouble(const char*& buf) {
21 // Fast but non-portable!
22 std::uint64_t val = (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
23 ++buf;
24 val <<= 8;
25 val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
26 ++buf;
27 val <<= 8;
28 val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
29 ++buf;
30 val <<= 8;
31 val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
32 ++buf;
33 val <<= 8;
34 val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
35 ++buf;
36 val <<= 8;
37 val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
38 ++buf;
39 val <<= 8;
40 val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
41 ++buf;
42 val <<= 8;
43 val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
44 ++buf;
45 return llvm::BitsToDouble(val);
46}
47
48WireDecoder::WireDecoder(raw_istream& is, unsigned int proto_rev) : m_is(is) {
49 // Start with a 1K temporary buffer. Use malloc instead of new so we can
50 // realloc.
51 m_allocated = 1024;
52 m_buf = static_cast<char*>(std::malloc(m_allocated));
53 m_proto_rev = proto_rev;
54 m_error = nullptr;
55}
56
57WireDecoder::~WireDecoder() { std::free(m_buf); }
58
59bool WireDecoder::ReadDouble(double* val) {
60 const char* buf;
61 if (!Read(&buf, 8)) return false;
62 *val = ::ReadDouble(buf);
63 return true;
64}
65
66void WireDecoder::Realloc(std::size_t len) {
67 // Double current buffer size until we have enough space.
68 if (m_allocated >= len) return;
69 std::size_t newlen = m_allocated * 2;
70 while (newlen < len) newlen *= 2;
71 m_buf = static_cast<char*>(std::realloc(m_buf, newlen));
72 m_allocated = newlen;
73}
74
75bool WireDecoder::ReadType(NT_Type* type) {
76 unsigned int itype;
77 if (!Read8(&itype)) return false;
78 // Convert from byte value to enum
79 switch (itype) {
80 case 0x00:
81 *type = NT_BOOLEAN;
82 break;
83 case 0x01:
84 *type = NT_DOUBLE;
85 break;
86 case 0x02:
87 *type = NT_STRING;
88 break;
89 case 0x03:
90 *type = NT_RAW;
91 break;
92 case 0x10:
93 *type = NT_BOOLEAN_ARRAY;
94 break;
95 case 0x11:
96 *type = NT_DOUBLE_ARRAY;
97 break;
98 case 0x12:
99 *type = NT_STRING_ARRAY;
100 break;
101 case 0x20:
102 *type = NT_RPC;
103 break;
104 default:
105 *type = NT_UNASSIGNED;
106 m_error = "unrecognized value type";
107 return false;
108 }
109 return true;
110}
111
112std::shared_ptr<Value> WireDecoder::ReadValue(NT_Type type) {
113 switch (type) {
114 case NT_BOOLEAN: {
115 unsigned int v;
116 if (!Read8(&v)) return nullptr;
117 return Value::MakeBoolean(v != 0);
118 }
119 case NT_DOUBLE: {
120 double v;
121 if (!ReadDouble(&v)) return nullptr;
122 return Value::MakeDouble(v);
123 }
124 case NT_STRING: {
125 std::string v;
126 if (!ReadString(&v)) return nullptr;
127 return Value::MakeString(std::move(v));
128 }
129 case NT_RAW: {
130 if (m_proto_rev < 0x0300u) {
131 m_error = "received raw value in protocol < 3.0";
132 return nullptr;
133 }
134 std::string v;
135 if (!ReadString(&v)) return nullptr;
136 return Value::MakeRaw(std::move(v));
137 }
138 case NT_RPC: {
139 if (m_proto_rev < 0x0300u) {
140 m_error = "received RPC value in protocol < 3.0";
141 return nullptr;
142 }
143 std::string v;
144 if (!ReadString(&v)) return nullptr;
145 return Value::MakeRpc(std::move(v));
146 }
147 case NT_BOOLEAN_ARRAY: {
148 // size
149 unsigned int size;
150 if (!Read8(&size)) return nullptr;
151
152 // array values
153 const char* buf;
154 if (!Read(&buf, size)) return nullptr;
155 std::vector<int> v(size);
156 for (unsigned int i = 0; i < size; ++i)
157 v[i] = buf[i] ? 1 : 0;
158 return Value::MakeBooleanArray(std::move(v));
159 }
160 case NT_DOUBLE_ARRAY: {
161 // size
162 unsigned int size;
163 if (!Read8(&size)) return nullptr;
164
165 // array values
166 const char* buf;
167 if (!Read(&buf, size * 8)) return nullptr;
168 std::vector<double> v(size);
169 for (unsigned int i = 0; i < size; ++i)
170 v[i] = ::ReadDouble(buf);
171 return Value::MakeDoubleArray(std::move(v));
172 }
173 case NT_STRING_ARRAY: {
174 // size
175 unsigned int size;
176 if (!Read8(&size)) return nullptr;
177
178 // array values
179 std::vector<std::string> v(size);
180 for (unsigned int i = 0; i < size; ++i) {
181 if (!ReadString(&v[i])) return nullptr;
182 }
183 return Value::MakeStringArray(std::move(v));
184 }
185 default:
186 m_error = "invalid type when trying to read value";
187 return nullptr;
188 }
189}
190
191bool WireDecoder::ReadString(std::string* str) {
192 size_t len;
193 if (m_proto_rev < 0x0300u) {
194 unsigned int v;
195 if (!Read16(&v)) return false;
196 len = v;
197 } else {
198 unsigned long v;
199 if (!ReadUleb128(&v)) return false;
200 len = v;
201 }
202 const char* buf;
203 if (!Read(&buf, len)) return false;
204 *str = llvm::StringRef(buf, len);
205 return true;
206}