blob: 825bb3c3596becf9bec1d8025929b5969adea779 [file] [log] [blame]
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001#include "aos/json_to_flatbuffer.h"
2
3#include <cstddef>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cstdio>
James Kuszmaul3ae42262019-11-08 12:33:41 -08005#include <string_view>
6
Austin Schuh43c6a352019-09-30 22:22:10 -07007#include "aos/flatbuffer_utils.h"
Austin Schuhd7e252d2019-10-06 13:51:02 -07008#include "aos/json_tokenizer.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -07009#include "flatbuffers/flatbuffers.h"
10#include "flatbuffers/minireflect.h"
Austin Schuhe93d8642019-10-13 15:27:07 -070011#include "glog/logging.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -070012
13// TODO(austin): Can we just do an Offset<void> ? It doesn't matter, so maybe
14// just say that.
15//
16// TODO(austin): I've yet to see how to create an ET_UTYPE, so I don't know what
17// one is and how to test it. So everything rejects it.
18
19namespace aos {
Austin Schuh3e95e5d2019-09-20 00:08:54 -070020namespace {
21
22// Class to hold one of the 3 json types for an array.
23struct Element {
24 // The type.
25 enum class ElementType { INT, DOUBLE, OFFSET };
26
27 // Constructs an Element holding an integer.
28 Element(int64_t new_int_element)
29 : int_element(new_int_element), type(ElementType::INT) {}
30 // Constructs an Element holding an double.
31 Element(double new_double_element)
32 : double_element(new_double_element), type(ElementType::DOUBLE) {}
33 // Constructs an Element holding an Offset.
34 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
35 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
36
37 // Union for the various datatypes.
38 union {
39 int64_t int_element;
40 double double_element;
41 flatbuffers::Offset<flatbuffers::String> offset_element;
42 };
43
44 // And an enum signaling which one is in use.
45 ElementType type;
46};
47
48// Structure to represent a field element.
49struct FieldElement {
50 FieldElement(int new_field_index, int64_t int_element)
51 : element(int_element), field_index(new_field_index) {}
52 FieldElement(int new_field_index, double double_element)
53 : element(double_element), field_index(new_field_index) {}
54 FieldElement(int new_field_index,
55 flatbuffers::Offset<flatbuffers::String> offset_element)
56 : element(offset_element), field_index(new_field_index) {}
57
58 // Data to write.
59 Element element;
60 // Field index. The type table which this index is for is stored outside this
61 // object.
62 int field_index;
63};
64
Austin Schuh43c6a352019-09-30 22:22:10 -070065// Adds a single element. This assumes that vectors have been dealt with
66// already. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -080067bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -070068 ::std::vector<bool> *fields_in_use,
69 flatbuffers::FlatBufferBuilder *fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -080070bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
71 flatbuffers::FlatBufferBuilder *fbb);
72bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
73 flatbuffers::FlatBufferBuilder *fbb);
74bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -070075 flatbuffers::Offset<flatbuffers::String> offset_element,
76 flatbuffers::FlatBufferBuilder *fbb);
77
Brian Silvermancf4fb662021-02-10 17:54:53 -080078// Writes an array of FieldElement (with the definition in "type") to the
79// builder. Returns the offset of the resulting table.
80flatbuffers::uoffset_t WriteTable(FlatbufferType type,
Austin Schuh43c6a352019-09-30 22:22:10 -070081 const ::std::vector<FieldElement> &elements,
82 flatbuffers::FlatBufferBuilder *fbb) {
83 // End of a nested struct! Add it.
84 const flatbuffers::uoffset_t start = fbb->StartTable();
85
Brian Silvermancf4fb662021-02-10 17:54:53 -080086 ::std::vector<bool> fields_in_use(type.NumberFields(), false);
Austin Schuh43c6a352019-09-30 22:22:10 -070087
88 for (const FieldElement &field_element : elements) {
Brian Silvermancf4fb662021-02-10 17:54:53 -080089 AddSingleElement(type, field_element, &fields_in_use, fbb);
Austin Schuh43c6a352019-09-30 22:22:10 -070090 }
91
92 return fbb->EndTable(start);
93}
94
Austin Schuh3e95e5d2019-09-20 00:08:54 -070095// Class to parse JSON into a flatbuffer.
96//
97// The basic strategy is that we need to do everything backwards. So we need to
98// build up what we need to do fully in memory, then do it.
99//
100// The driver for this is that strings need to be fully created before the
101// tables that use them. Same for sub messages. But, we only know we have them
Austin Schuh43c6a352019-09-30 22:22:10 -0700102// all when the structure ends. So, store each sub message in a
103// FieldElement and put them in the table at the end when we finish up
104// each message. Same goes for vectors.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700105class JsonParser {
106 public:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800107 JsonParser(flatbuffers::FlatBufferBuilder *fbb) : fbb_(fbb) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700108 ~JsonParser() {}
109
110 // Parses the json into a flatbuffer. Returns either an empty vector on
111 // error, or a vector with the flatbuffer data in it.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800112 flatbuffers::Offset<flatbuffers::Table> Parse(const std::string_view data,
113 FlatbufferType type) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700114 flatbuffers::uoffset_t end = 0;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800115 bool result = DoParse(type, data, &end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700116
117 if (result) {
118 // On success, finish the table and build the vector.
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800119 return flatbuffers::Offset<flatbuffers::Table>(end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700120 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800121 return flatbuffers::Offset<flatbuffers::Table>(0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700122 }
123 }
124
125 private:
126 // Setters and getters for in_vector (at the current level of the stack)
127 bool in_vector() const { return stack_.back().in_vector; }
128 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
129
130 // Parses the flatbuffer. This is a second method so we can do easier
131 // cleanup at the top level. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800132 bool DoParse(FlatbufferType type, const std::string_view data,
133 flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700134
135 // Adds *_value for the provided field. If we are in a vector, queues the
Alex Perrycb7da4b2019-08-28 19:35:56 -0700136 // data up in vector_elements. Returns true on success.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700137 bool AddElement(int field_index, int64_t int_value);
138 bool AddElement(int field_index, double double_value);
139 bool AddElement(int field_index, const ::std::string &data);
140
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700141 // Finishes a vector for the provided field index. Returns true on success.
142 bool FinishVector(int field_index);
143
144 // Pushes an element as part of a vector. Returns true on success.
145 bool PushElement(flatbuffers::ElementaryType elementary_type,
146 int64_t int_value);
147 bool PushElement(flatbuffers::ElementaryType elementary_type,
148 double double_value);
149 bool PushElement(flatbuffers::ElementaryType elementary_type,
150 flatbuffers::Offset<flatbuffers::String> offset_value);
151
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800152 flatbuffers::FlatBufferBuilder *fbb_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700153
154 // This holds the state information that is needed as you recurse into
155 // nested structures.
156 struct FlatBufferContext {
157 // Type of the current type.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800158 FlatbufferType type;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700159 // If true, we are parsing a vector.
160 bool in_vector;
161 // The field index of the current field.
162 int field_index;
163 // Name of the current field.
164 ::std::string field_name;
165
166 // Field elements that need to be inserted.
167 ::std::vector<FieldElement> elements;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700168
169 // For scalar types (not strings, and not nested tables), the vector ends
170 // up being implemented as a start and end, and a block of data. So we
171 // can't just push offsets in as we go. We either need to reproduce the
172 // logic inside flatbuffers, or build up vectors of the data. Vectors will
173 // be a bit of extra stack space, but whatever.
174 //
175 // Strings and nested structures are vectors of offsets.
176 // into the vector. Once you get to the end, you build up a vector and
177 // push that into the field.
178 ::std::vector<Element> vector_elements;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700179 };
180 ::std::vector<FlatBufferContext> stack_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700181};
182
Brian Silvermancf4fb662021-02-10 17:54:53 -0800183bool JsonParser::DoParse(FlatbufferType type, const std::string_view data,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700184 flatbuffers::uoffset_t *table_end) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800185 ::std::vector<FlatbufferType> stack;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700186
187 Tokenizer t(data);
188
189 // Main loop. Run until we get an end.
190 while (true) {
191 Tokenizer::TokenType token = t.Next();
192
193 switch (token) {
194 case Tokenizer::TokenType::kEnd:
195 if (stack_.size() != 0) {
Austin Schuh217a9782019-12-21 23:02:50 -0800196 fprintf(stderr, "Failed to unwind stack all the way\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700197 return false;
198 } else {
199 return true;
200 }
201 break;
202 case Tokenizer::TokenType::kError:
203 return false;
204 break;
205
206 case Tokenizer::TokenType::kStartObject: // {
207 if (stack_.size() == 0) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800208 stack_.push_back({type, false, -1, "", {}, {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700209 } else {
210 int field_index = stack_.back().field_index;
211
Brian Silvermancf4fb662021-02-10 17:54:53 -0800212 if (!stack_.back().type.FieldIsSequence(field_index)) {
Austin Schuh217a9782019-12-21 23:02:50 -0800213 fprintf(stderr, "Field '%s' is not a sequence\n",
214 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700215 return false;
216 }
217
Brian Silvermancf4fb662021-02-10 17:54:53 -0800218 stack_.push_back({stack_.back().type.FieldType(field_index),
219 false,
220 -1,
221 "",
222 {},
223 {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700224 }
225 break;
226 case Tokenizer::TokenType::kEndObject: // }
227 if (stack_.size() == 0) {
228 // Somehow we popped more than we pushed. Error.
Austin Schuh217a9782019-12-21 23:02:50 -0800229 fprintf(stderr, "Empty stack\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700230 return false;
231 } else {
232 // End of a nested struct! Add it.
Austin Schuhd3936202020-04-07 20:11:07 -0700233 const flatbuffers::uoffset_t end =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800234 WriteTable(stack_.back().type, stack_.back().elements, fbb_);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700235
236 // We now want to talk about the parent structure. Pop the child.
237 stack_.pop_back();
238
239 if (stack_.size() == 0) {
240 // Instead of queueing it up in the stack, return it through the
241 // passed in variable.
242 *table_end = end;
243 } else {
244 // And now we can add it.
245 const int field_index = stack_.back().field_index;
246
247 // Do the right thing if we are in a vector.
248 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700249 stack_.back().vector_elements.emplace_back(
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700250 flatbuffers::Offset<flatbuffers::String>(end));
251 } else {
252 stack_.back().elements.emplace_back(
253 field_index, flatbuffers::Offset<flatbuffers::String>(end));
254 }
255 }
256 }
257 break;
258
259 case Tokenizer::TokenType::kStartArray: // [
260 if (stack_.size() == 0) {
261 // We don't support an array of structs at the root level.
262 return false;
263 }
264 // Sanity check that we aren't trying to make a vector of vectors.
265 if (in_vector()) {
266 return false;
267 }
268 set_in_vector(true);
269
270 break;
271 case Tokenizer::TokenType::kEndArray: { // ]
272 if (!in_vector()) {
273 return false;
274 }
275
276 const int field_index = stack_.back().field_index;
277
278 if (!FinishVector(field_index)) return false;
279
280 set_in_vector(false);
281 } break;
282
283 case Tokenizer::TokenType::kTrueValue: // true
284 case Tokenizer::TokenType::kFalseValue: // false
285 case Tokenizer::TokenType::kNumberValue: {
286 bool is_int = true;
287 double double_value;
288 long long int_value;
289 if (token == Tokenizer::TokenType::kTrueValue) {
290 int_value = 1;
291 } else if (token == Tokenizer::TokenType::kFalseValue) {
292 int_value = 0;
293 } else if (!t.FieldAsInt(&int_value)) {
294 if (t.FieldAsDouble(&double_value)) {
295 is_int = false;
296 } else {
297 fprintf(stderr, "Got a invalid number '%s'\n",
298 t.field_value().c_str());
299 return false;
300 }
301 }
302
303 const int field_index = stack_.back().field_index;
304
305 if (is_int) {
306 // No need to get too stressed about bool vs int. Convert them all.
307 int64_t val = int_value;
308 if (!AddElement(field_index, val)) return false;
309 } else {
310 if (!AddElement(field_index, double_value)) return false;
311 }
312 } break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700313 case Tokenizer::TokenType::kStringValue: // string value
314 {
315 const int field_index = stack_.back().field_index;
316
317 if (!AddElement(field_index, t.field_value())) return false;
318 } break;
319 case Tokenizer::TokenType::kField: // field name
320 {
321 stack_.back().field_name = t.field_name();
Brian Silvermancf4fb662021-02-10 17:54:53 -0800322 stack_.back().field_index =
323 stack_.back().type.FieldIndex(stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700324
325 if (stack_.back().field_index == -1) {
Austin Schuh217a9782019-12-21 23:02:50 -0800326 fprintf(stderr, "Invalid field name '%s'\n",
327 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700328 return false;
329 }
330 } break;
331 }
332 }
333 return false;
334}
335
336bool JsonParser::AddElement(int field_index, int64_t int_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800337 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800338 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700339 return false;
340 }
341
342 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700343 stack_.back().vector_elements.emplace_back(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700344 } else {
345 stack_.back().elements.emplace_back(field_index, int_value);
346 }
347 return true;
348}
349
350bool JsonParser::AddElement(int field_index, double double_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800351 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800352 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700353 return false;
354 }
355
356 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700357 stack_.back().vector_elements.emplace_back(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700358 } else {
359 stack_.back().elements.emplace_back(field_index, double_value);
360 }
361 return true;
362}
363
364bool JsonParser::AddElement(int field_index, const ::std::string &data) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800365 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800366 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700367 return false;
368 }
369
Alex Perrycb7da4b2019-08-28 19:35:56 -0700370 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800371 stack_.back().type.FieldElementaryType(field_index);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700372 switch (elementary_type) {
373 case flatbuffers::ET_CHAR:
374 case flatbuffers::ET_UCHAR:
375 case flatbuffers::ET_SHORT:
376 case flatbuffers::ET_USHORT:
377 case flatbuffers::ET_INT:
378 case flatbuffers::ET_UINT:
379 case flatbuffers::ET_LONG:
380 case flatbuffers::ET_ULONG:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800381 if (stack_.back().type.FieldIsEnum(field_index)) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700382 // We have an enum.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800383 const FlatbufferType type = stack_.back().type;
384 const FlatbufferType enum_type = type.FieldType(field_index);
385 CHECK(enum_type.IsEnum());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700386
Brian Silvermancf4fb662021-02-10 17:54:53 -0800387 const std::optional<int64_t> int_value = enum_type.EnumValue(data);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700388
Brian Silvermancf4fb662021-02-10 17:54:53 -0800389 if (!int_value) {
390 const std::string_view name = type.FieldName(field_index);
391 fprintf(stderr, "Enum value '%s' not found for field '%.*s'\n",
392 data.c_str(), static_cast<int>(name.size()), name.data());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700393 return false;
394 }
395
396 if (in_vector()) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800397 stack_.back().vector_elements.emplace_back(*int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700398 } else {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800399 stack_.back().elements.emplace_back(field_index, *int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700400 }
401 return true;
402 }
403 case flatbuffers::ET_UTYPE:
404 case flatbuffers::ET_BOOL:
405 case flatbuffers::ET_FLOAT:
406 case flatbuffers::ET_DOUBLE:
407 case flatbuffers::ET_STRING:
408 case flatbuffers::ET_SEQUENCE:
409 break;
410 }
411
412 if (in_vector()) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800413 stack_.back().vector_elements.emplace_back(fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700414 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800415 stack_.back().elements.emplace_back(field_index, fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700416 }
417 return true;
418}
419
Brian Silvermancf4fb662021-02-10 17:54:53 -0800420bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -0700421 ::std::vector<bool> *fields_in_use,
422 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700423 if ((*fields_in_use)[field_element.field_index]) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800424 const std::string_view name = type.FieldName(field_element.field_index);
425 fprintf(stderr, "Duplicate field: '%.*s'\n", static_cast<int>(name.size()),
426 name.data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700427 return false;
428 }
429
430 (*fields_in_use)[field_element.field_index] = true;
431
432 switch (field_element.element.type) {
433 case Element::ElementType::INT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800434 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700435 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700436 case Element::ElementType::DOUBLE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800437 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700438 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700439 case Element::ElementType::OFFSET:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800440 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700441 field_element.element.offset_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700442 }
443 return false;
444}
445
Brian Silvermancf4fb662021-02-10 17:54:53 -0800446bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
447 flatbuffers::FlatBufferBuilder *fbb
Austin Schuh43c6a352019-09-30 22:22:10 -0700448
449) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700450 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
451 static_cast<flatbuffers::voffset_t>(field_index));
452
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700453 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800454 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700455 switch (elementary_type) {
456 case flatbuffers::ET_BOOL:
Brian Silverman69069232021-11-10 12:26:52 -0800457 fbb->AddElement<bool>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700458 return true;
459 case flatbuffers::ET_CHAR:
Brian Silverman69069232021-11-10 12:26:52 -0800460 fbb->AddElement<int8_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700461 return true;
462 case flatbuffers::ET_UCHAR:
Brian Silverman69069232021-11-10 12:26:52 -0800463 fbb->AddElement<uint8_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700464 return true;
465 case flatbuffers::ET_SHORT:
Brian Silverman69069232021-11-10 12:26:52 -0800466 fbb->AddElement<int16_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700467 return true;
468 case flatbuffers::ET_USHORT:
Brian Silverman69069232021-11-10 12:26:52 -0800469 fbb->AddElement<uint16_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700470 return true;
471 case flatbuffers::ET_INT:
Brian Silverman69069232021-11-10 12:26:52 -0800472 fbb->AddElement<int32_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700473 return true;
474 case flatbuffers::ET_UINT:
Brian Silverman69069232021-11-10 12:26:52 -0800475 fbb->AddElement<uint32_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700476 return true;
477 case flatbuffers::ET_LONG:
Brian Silverman69069232021-11-10 12:26:52 -0800478 fbb->AddElement<int64_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700479 return true;
480 case flatbuffers::ET_ULONG:
Brian Silverman69069232021-11-10 12:26:52 -0800481 fbb->AddElement<uint64_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700482 return true;
483 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800484 fbb->AddElement<float>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700485 return true;
486 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800487 fbb->AddElement<double>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700488 return true;
489 case flatbuffers::ET_STRING:
490 case flatbuffers::ET_UTYPE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800491 case flatbuffers::ET_SEQUENCE: {
492 const std::string_view name = type.FieldName(field_index);
493 fprintf(stderr,
494 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
495 static_cast<int>(name.size()), name.data(),
496 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700497 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800498 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700499 };
500 return false;
501}
502
Brian Silvermancf4fb662021-02-10 17:54:53 -0800503bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
Austin Schuh43c6a352019-09-30 22:22:10 -0700504 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700505 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
506 static_cast<flatbuffers::voffset_t>(field_index));
507
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700508 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800509 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700510 switch (elementary_type) {
511 case flatbuffers::ET_UTYPE:
512 case flatbuffers::ET_BOOL:
513 case flatbuffers::ET_CHAR:
514 case flatbuffers::ET_UCHAR:
515 case flatbuffers::ET_SHORT:
516 case flatbuffers::ET_USHORT:
517 case flatbuffers::ET_INT:
518 case flatbuffers::ET_UINT:
519 case flatbuffers::ET_LONG:
520 case flatbuffers::ET_ULONG:
521 case flatbuffers::ET_STRING:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800522 case flatbuffers::ET_SEQUENCE: {
523 const std::string_view name = type.FieldName(field_index);
524 fprintf(stderr,
525 "Mismatched type for field '%.*s'. Got: double, expected %s\n",
526 static_cast<int>(name.size()), name.data(),
527 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700528 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800529 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700530 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800531 fbb->AddElement<float>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700532 return true;
533 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800534 fbb->AddElement<double>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700535 return true;
536 }
537 return false;
538}
Brian Silvermancf4fb662021-02-10 17:54:53 -0800539bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700540 flatbuffers::Offset<flatbuffers::String> offset_element,
541 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700542 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
543 static_cast<flatbuffers::voffset_t>(field_index));
544
545 // Vectors will always be Offset<>'s.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800546 if (type.FieldIsRepeating(field_index)) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700547 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700548 return true;
549 }
550
551 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800552 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700553 switch (elementary_type) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700554 case flatbuffers::ET_CHAR:
555 case flatbuffers::ET_UCHAR:
556 case flatbuffers::ET_SHORT:
557 case flatbuffers::ET_USHORT:
558 case flatbuffers::ET_INT:
559 case flatbuffers::ET_UINT:
560 case flatbuffers::ET_LONG:
561 case flatbuffers::ET_ULONG:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700562 case flatbuffers::ET_UTYPE:
563 case flatbuffers::ET_BOOL:
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700564 case flatbuffers::ET_FLOAT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800565 case flatbuffers::ET_DOUBLE: {
566 const std::string_view name = type.FieldName(field_index);
567 fprintf(stderr,
568 "Mismatched type for field '%.*s'. Got: string, expected %s\n",
569 static_cast<int>(name.size()), name.data(),
570 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700571 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800572 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700573 case flatbuffers::ET_STRING:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700574 case flatbuffers::ET_SEQUENCE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700575 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700576 return true;
577 }
578 return false;
579}
580
581bool JsonParser::FinishVector(int field_index) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800582 // Vectors have a start (unfortunately which needs to know the size)
James Kuszmaul65541cb2022-11-08 14:53:47 -0800583 const size_t inline_size = stack_.back().type.FieldInlineSize(field_index);
584 fbb_->StartVector(stack_.back().vector_elements.size(), inline_size,
585 /*align=*/inline_size);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700586
587 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800588 stack_.back().type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700589
590 // Then the data (in reverse order for some reason...)
Alex Perrycb7da4b2019-08-28 19:35:56 -0700591 for (size_t i = stack_.back().vector_elements.size(); i > 0;) {
592 const Element &element = stack_.back().vector_elements[--i];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700593 switch (element.type) {
594 case Element::ElementType::INT:
595 if (!PushElement(elementary_type, element.int_element)) return false;
596 break;
597 case Element::ElementType::DOUBLE:
598 if (!PushElement(elementary_type, element.double_element)) return false;
599 break;
600 case Element::ElementType::OFFSET:
601 if (!PushElement(elementary_type, element.offset_element)) return false;
602 break;
603 }
604 }
605
606 // Then an End which is placed into the buffer the same as any other offset.
607 stack_.back().elements.emplace_back(
608 field_index, flatbuffers::Offset<flatbuffers::String>(
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800609 fbb_->EndVector(stack_.back().vector_elements.size())));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700610 stack_.back().vector_elements.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700611 return true;
612}
613
614bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
615 int64_t int_value) {
616 switch (elementary_type) {
617 case flatbuffers::ET_BOOL:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800618 fbb_->PushElement<bool>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700619 return true;
620 case flatbuffers::ET_CHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800621 fbb_->PushElement<int8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700622 return true;
623 case flatbuffers::ET_UCHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800624 fbb_->PushElement<uint8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700625 return true;
626 case flatbuffers::ET_SHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800627 fbb_->PushElement<int16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700628 return true;
629 case flatbuffers::ET_USHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800630 fbb_->PushElement<uint16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700631 return true;
632 case flatbuffers::ET_INT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800633 fbb_->PushElement<int32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700634 return true;
635 case flatbuffers::ET_UINT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800636 fbb_->PushElement<uint32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700637 return true;
638 case flatbuffers::ET_LONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800639 fbb_->PushElement<int64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700640 return true;
641 case flatbuffers::ET_ULONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800642 fbb_->PushElement<uint64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700643 return true;
644 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800645 fbb_->PushElement<float>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700646 return true;
647 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800648 fbb_->PushElement<double>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700649 return true;
650 case flatbuffers::ET_STRING:
651 case flatbuffers::ET_UTYPE:
652 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800653 fprintf(stderr,
654 "Mismatched type for field '%s'. Got: integer, expected %s\n",
655 stack_.back().field_name.c_str(),
656 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700657 return false;
658 };
659 return false;
660}
661
662bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
663 double double_value) {
664 switch (elementary_type) {
665 case flatbuffers::ET_UTYPE:
666 case flatbuffers::ET_BOOL:
667 case flatbuffers::ET_CHAR:
668 case flatbuffers::ET_UCHAR:
669 case flatbuffers::ET_SHORT:
670 case flatbuffers::ET_USHORT:
671 case flatbuffers::ET_INT:
672 case flatbuffers::ET_UINT:
673 case flatbuffers::ET_LONG:
674 case flatbuffers::ET_ULONG:
675 case flatbuffers::ET_STRING:
676 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800677 fprintf(stderr,
678 "Mismatched type for field '%s'. Got: double, expected %s\n",
679 stack_.back().field_name.c_str(),
680 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700681 return false;
682 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800683 fbb_->PushElement<float>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700684 return true;
685 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800686 fbb_->PushElement<double>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700687 return true;
688 }
689 return false;
690}
691
692bool JsonParser::PushElement(
693 flatbuffers::ElementaryType elementary_type,
694 flatbuffers::Offset<flatbuffers::String> offset_value) {
695 switch (elementary_type) {
696 case flatbuffers::ET_UTYPE:
697 case flatbuffers::ET_BOOL:
698 case flatbuffers::ET_CHAR:
699 case flatbuffers::ET_UCHAR:
700 case flatbuffers::ET_SHORT:
701 case flatbuffers::ET_USHORT:
702 case flatbuffers::ET_INT:
703 case flatbuffers::ET_UINT:
704 case flatbuffers::ET_LONG:
705 case flatbuffers::ET_ULONG:
706 case flatbuffers::ET_FLOAT:
707 case flatbuffers::ET_DOUBLE:
Austin Schuh217a9782019-12-21 23:02:50 -0800708 fprintf(stderr,
709 "Mismatched type for field '%s'. Got: sequence, expected %s\n",
710 stack_.back().field_name.c_str(),
711 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700712 return false;
713 case flatbuffers::ET_STRING:
714 case flatbuffers::ET_SEQUENCE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800715 fbb_->PushElement(offset_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700716 return true;
717 }
718 return false;
719}
720
721} // namespace
722
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800723flatbuffers::Offset<flatbuffers::Table> JsonToFlatbuffer(
Brian Silvermancf4fb662021-02-10 17:54:53 -0800724 const std::string_view data, FlatbufferType type,
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800725 flatbuffers::FlatBufferBuilder *fbb) {
726 JsonParser p(fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800727 return p.Parse(data, type);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800728}
729
Brian Silvermancf4fb662021-02-10 17:54:53 -0800730flatbuffers::DetachedBuffer JsonToFlatbuffer(const std::string_view data,
731 FlatbufferType type) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800732 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -0800733 fbb.ForceDefaults(true);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800734
735 const flatbuffers::Offset<flatbuffers::Table> result =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800736 JsonToFlatbuffer(data, type, &fbb);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800737 if (result.o != 0) {
738 fbb.Finish(result);
739
740 return fbb.Release();
741 } else {
742 // Otherwise return an empty vector.
743 return flatbuffers::DetachedBuffer();
744 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700745}
746
Austin Schuhd3936202020-04-07 20:11:07 -0700747namespace {
748
749// A visitor which manages skipping the contents of vectors that are longer than
750// a specified threshold.
751class TruncatingStringVisitor : public flatbuffers::IterationVisitor {
752 public:
753 TruncatingStringVisitor(size_t max_vector_size, std::string delimiter,
754 bool quotes, std::string indent, bool vdelimited)
755 : max_vector_size_(max_vector_size),
756 to_string_(delimiter, quotes, indent, vdelimited) {}
757 ~TruncatingStringVisitor() override {}
758
759 void StartSequence() override {
760 if (should_skip()) return;
761 to_string_.StartSequence();
762 }
763 void EndSequence() override {
764 if (should_skip()) return;
765 to_string_.EndSequence();
766 }
767 void Field(size_t field_idx, size_t set_idx, flatbuffers::ElementaryType type,
Austin Schuh7c75e582020-11-14 16:41:18 -0800768 bool is_repeating, const flatbuffers::TypeTable *type_table,
Austin Schuhd3936202020-04-07 20:11:07 -0700769 const char *name, const uint8_t *val) override {
770 if (should_skip()) return;
Austin Schuh7c75e582020-11-14 16:41:18 -0800771 to_string_.Field(field_idx, set_idx, type, is_repeating, type_table, name,
Austin Schuhd3936202020-04-07 20:11:07 -0700772 val);
773 }
774 void UType(uint8_t value, const char *name) override {
775 if (should_skip()) return;
776 to_string_.UType(value, name);
777 }
778 void Bool(bool value) override {
779 if (should_skip()) return;
780 to_string_.Bool(value);
781 }
782 void Char(int8_t value, const char *name) override {
783 if (should_skip()) return;
784 to_string_.Char(value, name);
785 }
786 void UChar(uint8_t value, const char *name) override {
787 if (should_skip()) return;
788 to_string_.UChar(value, name);
789 }
790 void Short(int16_t value, const char *name) override {
791 if (should_skip()) return;
792 to_string_.Short(value, name);
793 }
794 void UShort(uint16_t value, const char *name) override {
795 if (should_skip()) return;
796 to_string_.UShort(value, name);
797 }
798 void Int(int32_t value, const char *name) override {
799 if (should_skip()) return;
800 to_string_.Int(value, name);
801 }
802 void UInt(uint32_t value, const char *name) override {
803 if (should_skip()) return;
804 to_string_.UInt(value, name);
805 }
806 void Long(int64_t value) override {
807 if (should_skip()) return;
808 to_string_.Long(value);
809 }
810 void ULong(uint64_t value) override {
811 if (should_skip()) return;
812 to_string_.ULong(value);
813 }
814 void Float(float value) override {
815 if (should_skip()) return;
816 to_string_.Float(value);
817 }
818 void Double(double value) override {
819 if (should_skip()) return;
820 to_string_.Double(value);
821 }
822 void String(const flatbuffers::String *value) override {
823 if (should_skip()) return;
824 to_string_.String(value);
825 }
826 void Unknown(const uint8_t *value) override {
827 if (should_skip()) return;
828 to_string_.Unknown(value);
829 }
830 void Element(size_t i, flatbuffers::ElementaryType type,
831 const flatbuffers::TypeTable *type_table,
832 const uint8_t *val) override {
833 if (should_skip()) return;
834 to_string_.Element(i, type, type_table, val);
835 }
836
837 virtual void StartVector(size_t size) override {
838 if (should_skip()) {
839 ++skip_levels_;
840 return;
841 }
842 if (size > max_vector_size_) {
843 ++skip_levels_;
Austin Schuh041fe9f2021-10-16 23:01:15 -0700844 to_string_.s += "[ \"... " + std::to_string(size) + " elements ...\" ]";
Austin Schuhd3936202020-04-07 20:11:07 -0700845 return;
846 }
847 to_string_.StartVector(size);
848 }
849 virtual void EndVector() override {
850 if (should_skip()) {
851 --skip_levels_;
852 return;
853 }
854 to_string_.EndVector();
855 }
856
857 std::string &string() { return to_string_.s; }
858
859 private:
860 bool should_skip() const { return skip_levels_ > 0; }
861
862 const size_t max_vector_size_;
863 flatbuffers::ToStringVisitor to_string_;
864 int skip_levels_ = 0;
865};
866
867} // namespace
868
Austin Schuhe93d8642019-10-13 15:27:07 -0700869::std::string TableFlatbufferToJson(const flatbuffers::Table *t,
870 const ::flatbuffers::TypeTable *typetable,
Ravago Jonescf453ab2020-05-06 21:14:53 -0700871 JsonOptions json_options) {
Austin Schuhe93d8642019-10-13 15:27:07 -0700872 // It is pretty common to get passed in a nullptr when a test fails. Rather
873 // than CHECK, return a more user friendly result.
874 if (t == nullptr) {
875 return "null";
876 }
Ravago Jonescf453ab2020-05-06 21:14:53 -0700877 TruncatingStringVisitor tostring_visitor(
878 json_options.max_vector_size, json_options.multi_line ? "\n" : " ", true,
879 json_options.multi_line ? " " : "", json_options.multi_line);
Austin Schuhe93d8642019-10-13 15:27:07 -0700880 flatbuffers::IterateObject(reinterpret_cast<const uint8_t *>(t), typetable,
881 &tostring_visitor);
Austin Schuhd3936202020-04-07 20:11:07 -0700882 return tostring_visitor.string();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700883}
884
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700885} // namespace aos