blob: 13a3a3873ee1930eb8d9694fc197288ce584b979 [file] [log] [blame]
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001#include "aos/json_to_flatbuffer.h"
2
3#include <cstddef>
4#include "stdio.h"
5
Austin Schuhd339a9b2019-10-05 21:33:32 -07006#include "absl/strings/string_view.h"
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 {
20
21// Finds the field index in the table given the name.
22int FieldIndex(const flatbuffers::TypeTable *typetable,
23 const char *field_name) {
24 CHECK(typetable->values == nullptr);
25 for (size_t i = 0; i < typetable->num_elems; ++i) {
26 if (strcmp(field_name, typetable->names[i]) == 0) {
27 return i;
28 }
29 }
30 return -1;
31}
32
33namespace {
34
35// Class to hold one of the 3 json types for an array.
36struct Element {
37 // The type.
38 enum class ElementType { INT, DOUBLE, OFFSET };
39
40 // Constructs an Element holding an integer.
41 Element(int64_t new_int_element)
42 : int_element(new_int_element), type(ElementType::INT) {}
43 // Constructs an Element holding an double.
44 Element(double new_double_element)
45 : double_element(new_double_element), type(ElementType::DOUBLE) {}
46 // Constructs an Element holding an Offset.
47 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
48 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
49
50 // Union for the various datatypes.
51 union {
52 int64_t int_element;
53 double double_element;
54 flatbuffers::Offset<flatbuffers::String> offset_element;
55 };
56
57 // And an enum signaling which one is in use.
58 ElementType type;
59};
60
61// Structure to represent a field element.
62struct FieldElement {
63 FieldElement(int new_field_index, int64_t int_element)
64 : element(int_element), field_index(new_field_index) {}
65 FieldElement(int new_field_index, double double_element)
66 : element(double_element), field_index(new_field_index) {}
67 FieldElement(int new_field_index,
68 flatbuffers::Offset<flatbuffers::String> offset_element)
69 : element(offset_element), field_index(new_field_index) {}
70
71 // Data to write.
72 Element element;
73 // Field index. The type table which this index is for is stored outside this
74 // object.
75 int field_index;
76};
77
Austin Schuh43c6a352019-09-30 22:22:10 -070078// Adds a single element. This assumes that vectors have been dealt with
79// already. Returns true on success.
80bool AddSingleElement(const flatbuffers::TypeTable *typetable,
81 const FieldElement &field_element,
82 ::std::vector<bool> *fields_in_use,
83 flatbuffers::FlatBufferBuilder *fbb);
84bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
85 int64_t int_value, flatbuffers::FlatBufferBuilder *fbb);
86bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
87 double double_value, flatbuffers::FlatBufferBuilder *fbb);
88bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
89 flatbuffers::Offset<flatbuffers::String> offset_element,
90 flatbuffers::FlatBufferBuilder *fbb);
91
92
93// Writes an array of FieldElement (with the definition in the type
94// table) to the builder. Returns the offset of the table.
95flatbuffers::uoffset_t WriteTable(const flatbuffers::TypeTable *typetable,
96 const ::std::vector<FieldElement> &elements,
97 flatbuffers::FlatBufferBuilder *fbb) {
98 // End of a nested struct! Add it.
99 const flatbuffers::uoffset_t start = fbb->StartTable();
100
101 ::std::vector<bool> fields_in_use(typetable->num_elems, false);
102
103 for (const FieldElement &field_element : elements) {
104 AddSingleElement(typetable, field_element, &fields_in_use, fbb);
105 }
106
107 return fbb->EndTable(start);
108}
109
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700110// Class to parse JSON into a flatbuffer.
111//
112// The basic strategy is that we need to do everything backwards. So we need to
113// build up what we need to do fully in memory, then do it.
114//
115// The driver for this is that strings need to be fully created before the
116// tables that use them. Same for sub messages. But, we only know we have them
Austin Schuh43c6a352019-09-30 22:22:10 -0700117// all when the structure ends. So, store each sub message in a
118// FieldElement and put them in the table at the end when we finish up
119// each message. Same goes for vectors.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700120class JsonParser {
121 public:
122 JsonParser() { fbb_.ForceDefaults(1); }
123 ~JsonParser() {}
124
125 // Parses the json into a flatbuffer. Returns either an empty vector on
126 // error, or a vector with the flatbuffer data in it.
Austin Schuhe93d8642019-10-13 15:27:07 -0700127 flatbuffers::DetachedBuffer Parse(const absl::string_view data,
128 const flatbuffers::TypeTable *typetable) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700129 flatbuffers::uoffset_t end = 0;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700130 bool result = DoParse(typetable, data, &end);
131
132 if (result) {
133 // On success, finish the table and build the vector.
134 auto o = flatbuffers::Offset<flatbuffers::Table>(end);
135 fbb_.Finish(o);
136
Austin Schuhe93d8642019-10-13 15:27:07 -0700137 return fbb_.Release();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700138 } else {
139 // Otherwise return an empty vector.
Austin Schuhe93d8642019-10-13 15:27:07 -0700140 return flatbuffers::DetachedBuffer();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700141 }
142 }
143
144 private:
145 // Setters and getters for in_vector (at the current level of the stack)
146 bool in_vector() const { return stack_.back().in_vector; }
147 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
148
149 // Parses the flatbuffer. This is a second method so we can do easier
150 // cleanup at the top level. Returns true on success.
Austin Schuhd339a9b2019-10-05 21:33:32 -0700151 bool DoParse(const flatbuffers::TypeTable *typetable,
152 const absl::string_view data, flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700153
154 // Adds *_value for the provided field. If we are in a vector, queues the
155 // data up in vector_elements_. Returns true on success.
156 bool AddElement(int field_index, int64_t int_value);
157 bool AddElement(int field_index, double double_value);
158 bool AddElement(int field_index, const ::std::string &data);
159
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700160 // Finishes a vector for the provided field index. Returns true on success.
161 bool FinishVector(int field_index);
162
163 // Pushes an element as part of a vector. Returns true on success.
164 bool PushElement(flatbuffers::ElementaryType elementary_type,
165 int64_t int_value);
166 bool PushElement(flatbuffers::ElementaryType elementary_type,
167 double double_value);
168 bool PushElement(flatbuffers::ElementaryType elementary_type,
169 flatbuffers::Offset<flatbuffers::String> offset_value);
170
171 flatbuffers::FlatBufferBuilder fbb_;
172
173 // This holds the state information that is needed as you recurse into
174 // nested structures.
175 struct FlatBufferContext {
176 // Type of the current type.
177 const flatbuffers::TypeTable *typetable;
178 // If true, we are parsing a vector.
179 bool in_vector;
180 // The field index of the current field.
181 int field_index;
182 // Name of the current field.
183 ::std::string field_name;
184
185 // Field elements that need to be inserted.
186 ::std::vector<FieldElement> elements;
187 };
188 ::std::vector<FlatBufferContext> stack_;
189
190 // For scalar types (not strings, and not nested tables), the vector ends
191 // up being implemented as a start and end, and a block of data. So we
192 // can't just push offsets in as we go. We either need to reproduce the
193 // logic inside flatbuffers, or build up vectors of the data. Vectors will
194 // be a bit of extra stack space, but whatever.
195 //
196 // Strings and nested structures are vectors of offsets.
197 // into the vector. Once you get to the end, you build up a vector and
198 // push that into the field.
199 ::std::vector<Element> vector_elements_;
200};
201
202bool JsonParser::DoParse(const flatbuffers::TypeTable *typetable,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700203 const absl::string_view data,
204 flatbuffers::uoffset_t *table_end) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700205 ::std::vector<const flatbuffers::TypeTable *> stack;
206
207 Tokenizer t(data);
208
209 // Main loop. Run until we get an end.
210 while (true) {
211 Tokenizer::TokenType token = t.Next();
212
213 switch (token) {
214 case Tokenizer::TokenType::kEnd:
215 if (stack_.size() != 0) {
216 printf("Failed to unwind stack all the way\n");
217 return false;
218 } else {
219 return true;
220 }
221 break;
222 case Tokenizer::TokenType::kError:
223 return false;
224 break;
225
226 case Tokenizer::TokenType::kStartObject: // {
227 if (stack_.size() == 0) {
228 stack_.push_back({typetable, false, -1, "", {}});
229 } else {
230 int field_index = stack_.back().field_index;
231
232 const flatbuffers::TypeCode &type_code =
233 stack_.back().typetable->type_codes[field_index];
234
235 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
236 printf("Field '%s' is not a sequence\n",
237 stack_.back().field_name.c_str());
238 return false;
239 }
240
241 flatbuffers::TypeFunction type_function =
242 stack_.back().typetable->type_refs[type_code.sequence_ref];
243
244 stack_.push_back({type_function(), false, -1, "", {}});
245 }
246 break;
247 case Tokenizer::TokenType::kEndObject: // }
248 if (stack_.size() == 0) {
249 // Somehow we popped more than we pushed. Error.
250 printf("Empty stack\n");
251 return false;
252 } else {
253 // End of a nested struct! Add it.
Austin Schuh43c6a352019-09-30 22:22:10 -0700254 const flatbuffers::uoffset_t end = WriteTable(
255 stack_.back().typetable, stack_.back().elements, &fbb_);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700256
257 // We now want to talk about the parent structure. Pop the child.
258 stack_.pop_back();
259
260 if (stack_.size() == 0) {
261 // Instead of queueing it up in the stack, return it through the
262 // passed in variable.
263 *table_end = end;
264 } else {
265 // And now we can add it.
266 const int field_index = stack_.back().field_index;
267
268 // Do the right thing if we are in a vector.
269 if (in_vector()) {
270 vector_elements_.emplace_back(
271 flatbuffers::Offset<flatbuffers::String>(end));
272 } else {
273 stack_.back().elements.emplace_back(
274 field_index, flatbuffers::Offset<flatbuffers::String>(end));
275 }
276 }
277 }
278 break;
279
280 case Tokenizer::TokenType::kStartArray: // [
281 if (stack_.size() == 0) {
282 // We don't support an array of structs at the root level.
283 return false;
284 }
285 // Sanity check that we aren't trying to make a vector of vectors.
286 if (in_vector()) {
287 return false;
288 }
289 set_in_vector(true);
290
291 break;
292 case Tokenizer::TokenType::kEndArray: { // ]
293 if (!in_vector()) {
294 return false;
295 }
296
297 const int field_index = stack_.back().field_index;
298
299 if (!FinishVector(field_index)) return false;
300
301 set_in_vector(false);
302 } break;
303
304 case Tokenizer::TokenType::kTrueValue: // true
305 case Tokenizer::TokenType::kFalseValue: // false
306 case Tokenizer::TokenType::kNumberValue: {
307 bool is_int = true;
308 double double_value;
309 long long int_value;
310 if (token == Tokenizer::TokenType::kTrueValue) {
311 int_value = 1;
312 } else if (token == Tokenizer::TokenType::kFalseValue) {
313 int_value = 0;
314 } else if (!t.FieldAsInt(&int_value)) {
315 if (t.FieldAsDouble(&double_value)) {
316 is_int = false;
317 } else {
318 fprintf(stderr, "Got a invalid number '%s'\n",
319 t.field_value().c_str());
320 return false;
321 }
322 }
323
324 const int field_index = stack_.back().field_index;
325
326 if (is_int) {
327 // No need to get too stressed about bool vs int. Convert them all.
328 int64_t val = int_value;
329 if (!AddElement(field_index, val)) return false;
330 } else {
331 if (!AddElement(field_index, double_value)) return false;
332 }
333 } break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700334 case Tokenizer::TokenType::kStringValue: // string value
335 {
336 const int field_index = stack_.back().field_index;
337
338 if (!AddElement(field_index, t.field_value())) return false;
339 } break;
340 case Tokenizer::TokenType::kField: // field name
341 {
342 stack_.back().field_name = t.field_name();
343 stack_.back().field_index = FieldIndex(
344 stack_.back().typetable, stack_.back().field_name.c_str());
345
346 if (stack_.back().field_index == -1) {
347 printf("Invalid field name '%s'\n", stack_.back().field_name.c_str());
348 return false;
349 }
350 } break;
351 }
352 }
353 return false;
354}
355
356bool JsonParser::AddElement(int field_index, int64_t int_value) {
357 flatbuffers::TypeCode type_code =
358 stack_.back().typetable->type_codes[field_index];
359
360 if (type_code.is_vector != in_vector()) {
361 printf("Type and json disagree on if we are in a vector or not\n");
362 return false;
363 }
364
365 if (in_vector()) {
366 vector_elements_.emplace_back(int_value);
367 } else {
368 stack_.back().elements.emplace_back(field_index, int_value);
369 }
370 return true;
371}
372
373bool JsonParser::AddElement(int field_index, double double_value) {
374 flatbuffers::TypeCode type_code =
375 stack_.back().typetable->type_codes[field_index];
376
377 if (type_code.is_vector != in_vector()) {
378 printf("Type and json disagree on if we are in a vector or not\n");
379 return false;
380 }
381
382 if (in_vector()) {
383 vector_elements_.emplace_back(double_value);
384 } else {
385 stack_.back().elements.emplace_back(field_index, double_value);
386 }
387 return true;
388}
389
390bool JsonParser::AddElement(int field_index, const ::std::string &data) {
391 flatbuffers::TypeCode type_code =
392 stack_.back().typetable->type_codes[field_index];
393
394 if (type_code.is_vector != in_vector()) {
395 printf("Type and json disagree on if we are in a vector or not\n");
396 return false;
397 }
398
399 if (in_vector()) {
400 vector_elements_.emplace_back(fbb_.CreateString(data));
401
402 } else {
403 stack_.back().elements.emplace_back(field_index, fbb_.CreateString(data));
404 }
405 return true;
406}
407
Austin Schuh43c6a352019-09-30 22:22:10 -0700408bool AddSingleElement(const flatbuffers::TypeTable *typetable,
409 const FieldElement &field_element,
410 ::std::vector<bool> *fields_in_use,
411 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700412 if ((*fields_in_use)[field_element.field_index]) {
413 printf("Duplicate field: '%s'\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700414 typetable->names[field_element.field_index]);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700415 return false;
416 }
417
418 (*fields_in_use)[field_element.field_index] = true;
419
420 switch (field_element.element.type) {
421 case Element::ElementType::INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700422 return AddSingleElement(typetable, field_element.field_index,
423 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700424 case Element::ElementType::DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700425 return AddSingleElement(typetable, field_element.field_index,
426 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700427 case Element::ElementType::OFFSET:
Austin Schuh43c6a352019-09-30 22:22:10 -0700428 return AddSingleElement(typetable, field_element.field_index,
429 field_element.element.offset_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700430 }
431 return false;
432}
433
Austin Schuh43c6a352019-09-30 22:22:10 -0700434bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
435 int64_t int_value, flatbuffers::FlatBufferBuilder *fbb
436
437) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700438 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
439 static_cast<flatbuffers::voffset_t>(field_index));
440
Austin Schuh43c6a352019-09-30 22:22:10 -0700441 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700442
443 const flatbuffers::ElementaryType elementary_type =
444 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
445 switch (elementary_type) {
446 case flatbuffers::ET_BOOL:
Austin Schuh43c6a352019-09-30 22:22:10 -0700447 fbb->AddElement<bool>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700448 return true;
449 case flatbuffers::ET_CHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700450 fbb->AddElement<int8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700451 return true;
452 case flatbuffers::ET_UCHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700453 fbb->AddElement<uint8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700454 return true;
455 case flatbuffers::ET_SHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700456 fbb->AddElement<int16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700457 return true;
458 case flatbuffers::ET_USHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700459 fbb->AddElement<uint16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700460 return true;
461 case flatbuffers::ET_INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700462 fbb->AddElement<int32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700463 return true;
464 case flatbuffers::ET_UINT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700465 fbb->AddElement<uint32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700466 return true;
467 case flatbuffers::ET_LONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700468 fbb->AddElement<int64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700469 return true;
470 case flatbuffers::ET_ULONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700471 fbb->AddElement<uint64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700472 return true;
473 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700474 fbb->AddElement<float>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700475 return true;
476 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700477 fbb->AddElement<double>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700478 return true;
479 case flatbuffers::ET_STRING:
480 case flatbuffers::ET_UTYPE:
481 case flatbuffers::ET_SEQUENCE:
482 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700483 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700484 ElementaryTypeName(elementary_type));
485 return false;
486 };
487 return false;
488}
489
Austin Schuh43c6a352019-09-30 22:22:10 -0700490bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
491 double double_value,
492 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700493 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
494 static_cast<flatbuffers::voffset_t>(field_index));
495
Austin Schuh43c6a352019-09-30 22:22:10 -0700496 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700497
498 const flatbuffers::ElementaryType elementary_type =
499 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
500 switch (elementary_type) {
501 case flatbuffers::ET_UTYPE:
502 case flatbuffers::ET_BOOL:
503 case flatbuffers::ET_CHAR:
504 case flatbuffers::ET_UCHAR:
505 case flatbuffers::ET_SHORT:
506 case flatbuffers::ET_USHORT:
507 case flatbuffers::ET_INT:
508 case flatbuffers::ET_UINT:
509 case flatbuffers::ET_LONG:
510 case flatbuffers::ET_ULONG:
511 case flatbuffers::ET_STRING:
512 case flatbuffers::ET_SEQUENCE:
513 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700514 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700515 ElementaryTypeName(elementary_type));
516 return false;
517 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700518 fbb->AddElement<float>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700519 return true;
520 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700521 fbb->AddElement<double>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700522 return true;
523 }
524 return false;
525}
Austin Schuh43c6a352019-09-30 22:22:10 -0700526bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
527 flatbuffers::Offset<flatbuffers::String> offset_element,
528 flatbuffers::FlatBufferBuilder *fbb) {
529 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700530
531 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
532 static_cast<flatbuffers::voffset_t>(field_index));
533
534 // Vectors will always be Offset<>'s.
535 if (type_code.is_vector) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700536 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700537 return true;
538 }
539
540 const flatbuffers::ElementaryType elementary_type =
541 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
542 switch (elementary_type) {
543 case flatbuffers::ET_UTYPE:
544 case flatbuffers::ET_BOOL:
545 case flatbuffers::ET_CHAR:
546 case flatbuffers::ET_UCHAR:
547 case flatbuffers::ET_SHORT:
548 case flatbuffers::ET_USHORT:
549 case flatbuffers::ET_INT:
550 case flatbuffers::ET_UINT:
551 case flatbuffers::ET_LONG:
552 case flatbuffers::ET_ULONG:
553 case flatbuffers::ET_FLOAT:
554 case flatbuffers::ET_DOUBLE:
555 printf("Mismatched type for field '%s'. Got: string, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700556 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700557 ElementaryTypeName(elementary_type));
558 return false;
559 case flatbuffers::ET_SEQUENCE:
560 case flatbuffers::ET_STRING:
Austin Schuh43c6a352019-09-30 22:22:10 -0700561 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700562 return true;
563 }
564 return false;
565}
566
567bool JsonParser::FinishVector(int field_index) {
568 flatbuffers::TypeCode type_code =
569 stack_.back().typetable->type_codes[field_index];
570
571 const flatbuffers::ElementaryType elementary_type =
572 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
573
574 // Vectors have a start (unfortunately which needs to know the size)
575 fbb_.StartVector(
576 vector_elements_.size(),
577 flatbuffers::InlineSize(elementary_type, stack_.back().typetable));
578
579 // Then the data (in reverse order for some reason...)
580 for (size_t i = vector_elements_.size(); i > 0;) {
581 const Element &element = vector_elements_[--i];
582 switch (element.type) {
583 case Element::ElementType::INT:
584 if (!PushElement(elementary_type, element.int_element)) return false;
585 break;
586 case Element::ElementType::DOUBLE:
587 if (!PushElement(elementary_type, element.double_element)) return false;
588 break;
589 case Element::ElementType::OFFSET:
590 if (!PushElement(elementary_type, element.offset_element)) return false;
591 break;
592 }
593 }
594
595 // Then an End which is placed into the buffer the same as any other offset.
596 stack_.back().elements.emplace_back(
597 field_index, flatbuffers::Offset<flatbuffers::String>(
598 fbb_.EndVector(vector_elements_.size())));
Austin Schuh9e2532d2019-10-06 14:01:15 -0700599 vector_elements_.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700600 return true;
601}
602
603bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
604 int64_t int_value) {
605 switch (elementary_type) {
606 case flatbuffers::ET_BOOL:
607 fbb_.PushElement<bool>(int_value);
608 return true;
609 case flatbuffers::ET_CHAR:
610 fbb_.PushElement<int8_t>(int_value);
611 return true;
612 case flatbuffers::ET_UCHAR:
613 fbb_.PushElement<uint8_t>(int_value);
614 return true;
615 case flatbuffers::ET_SHORT:
616 fbb_.PushElement<int16_t>(int_value);
617 return true;
618 case flatbuffers::ET_USHORT:
619 fbb_.PushElement<uint16_t>(int_value);
620 return true;
621 case flatbuffers::ET_INT:
622 fbb_.PushElement<int32_t>(int_value);
623 return true;
624 case flatbuffers::ET_UINT:
625 fbb_.PushElement<uint32_t>(int_value);
626 return true;
627 case flatbuffers::ET_LONG:
628 fbb_.PushElement<int64_t>(int_value);
629 return true;
630 case flatbuffers::ET_ULONG:
631 fbb_.PushElement<uint64_t>(int_value);
632 return true;
633 case flatbuffers::ET_FLOAT:
634 fbb_.PushElement<float>(int_value);
635 return true;
636 case flatbuffers::ET_DOUBLE:
637 fbb_.PushElement<double>(int_value);
638 return true;
639 case flatbuffers::ET_STRING:
640 case flatbuffers::ET_UTYPE:
641 case flatbuffers::ET_SEQUENCE:
642 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
643 stack_.back().field_name.c_str(),
644 ElementaryTypeName(elementary_type));
645 return false;
646 };
647 return false;
648}
649
650bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
651 double double_value) {
652 switch (elementary_type) {
653 case flatbuffers::ET_UTYPE:
654 case flatbuffers::ET_BOOL:
655 case flatbuffers::ET_CHAR:
656 case flatbuffers::ET_UCHAR:
657 case flatbuffers::ET_SHORT:
658 case flatbuffers::ET_USHORT:
659 case flatbuffers::ET_INT:
660 case flatbuffers::ET_UINT:
661 case flatbuffers::ET_LONG:
662 case flatbuffers::ET_ULONG:
663 case flatbuffers::ET_STRING:
664 case flatbuffers::ET_SEQUENCE:
665 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
666 stack_.back().field_name.c_str(),
667 ElementaryTypeName(elementary_type));
668 return false;
669 case flatbuffers::ET_FLOAT:
670 fbb_.PushElement<float>(double_value);
671 return true;
672 case flatbuffers::ET_DOUBLE:
673 fbb_.PushElement<double>(double_value);
674 return true;
675 }
676 return false;
677}
678
679bool JsonParser::PushElement(
680 flatbuffers::ElementaryType elementary_type,
681 flatbuffers::Offset<flatbuffers::String> offset_value) {
682 switch (elementary_type) {
683 case flatbuffers::ET_UTYPE:
684 case flatbuffers::ET_BOOL:
685 case flatbuffers::ET_CHAR:
686 case flatbuffers::ET_UCHAR:
687 case flatbuffers::ET_SHORT:
688 case flatbuffers::ET_USHORT:
689 case flatbuffers::ET_INT:
690 case flatbuffers::ET_UINT:
691 case flatbuffers::ET_LONG:
692 case flatbuffers::ET_ULONG:
693 case flatbuffers::ET_FLOAT:
694 case flatbuffers::ET_DOUBLE:
695 printf("Mismatched type for field '%s'. Got: sequence, expected %s\n",
696 stack_.back().field_name.c_str(),
697 ElementaryTypeName(elementary_type));
698 return false;
699 case flatbuffers::ET_STRING:
700 case flatbuffers::ET_SEQUENCE:
701 fbb_.PushElement(offset_value);
702 return true;
703 }
704 return false;
705}
706
707} // namespace
708
Austin Schuhe93d8642019-10-13 15:27:07 -0700709flatbuffers::DetachedBuffer JsonToFlatbuffer(
Austin Schuhd339a9b2019-10-05 21:33:32 -0700710 const absl::string_view data, const flatbuffers::TypeTable *typetable) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700711 JsonParser p;
712 return p.Parse(data, typetable);
713}
714
Austin Schuhe93d8642019-10-13 15:27:07 -0700715::std::string BufferFlatbufferToJson(const uint8_t *buffer,
716 const ::flatbuffers::TypeTable *typetable,
717 bool multi_line) {
718 // It is pretty common to get passed in a nullptr when a test fails. Rather
719 // than CHECK, return a more user friendly result.
720 if (buffer == nullptr) {
721 return "null";
722 }
723 return TableFlatbufferToJson(reinterpret_cast<const flatbuffers::Table *>(
724 flatbuffers::GetRoot<uint8_t>(buffer)),
725 typetable, multi_line);
726}
727
728::std::string TableFlatbufferToJson(const flatbuffers::Table *t,
729 const ::flatbuffers::TypeTable *typetable,
730 bool multi_line) {
731 // It is pretty common to get passed in a nullptr when a test fails. Rather
732 // than CHECK, return a more user friendly result.
733 if (t == nullptr) {
734 return "null";
735 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700736 ::flatbuffers::ToStringVisitor tostring_visitor(
737 multi_line ? "\n" : " ", true, multi_line ? " " : "", multi_line);
Austin Schuhe93d8642019-10-13 15:27:07 -0700738 flatbuffers::IterateObject(reinterpret_cast<const uint8_t *>(t), typetable,
739 &tostring_visitor);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700740 return tostring_visitor.s;
741}
742
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700743} // namespace aos