blob: 85e2d7f1891389802722272f7089a758de4695de [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 Schuh3e95e5d2019-09-20 00:08:54 -07008#include "aos/logging/logging.h"
Austin Schuhd7e252d2019-10-06 13:51:02 -07009#include "aos/json_tokenizer.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -070010#include "flatbuffers/flatbuffers.h"
11#include "flatbuffers/minireflect.h"
12
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 Schuhd339a9b2019-10-05 21:33:32 -0700127 ::std::vector<uint8_t> Parse(const absl::string_view data,
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700128 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
137 const uint8_t *buf = fbb_.GetBufferPointer();
138 const int size = fbb_.GetSize();
139 return ::std::vector<uint8_t>(buf, buf + size);
140 } else {
141 // Otherwise return an empty vector.
142 return ::std::vector<uint8_t>();
143 }
144 }
145
146 private:
147 // Setters and getters for in_vector (at the current level of the stack)
148 bool in_vector() const { return stack_.back().in_vector; }
149 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
150
151 // Parses the flatbuffer. This is a second method so we can do easier
152 // cleanup at the top level. Returns true on success.
Austin Schuhd339a9b2019-10-05 21:33:32 -0700153 bool DoParse(const flatbuffers::TypeTable *typetable,
154 const absl::string_view data, flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700155
156 // Adds *_value for the provided field. If we are in a vector, queues the
157 // data up in vector_elements_. Returns true on success.
158 bool AddElement(int field_index, int64_t int_value);
159 bool AddElement(int field_index, double double_value);
160 bool AddElement(int field_index, const ::std::string &data);
161
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700162 // Finishes a vector for the provided field index. Returns true on success.
163 bool FinishVector(int field_index);
164
165 // Pushes an element as part of a vector. Returns true on success.
166 bool PushElement(flatbuffers::ElementaryType elementary_type,
167 int64_t int_value);
168 bool PushElement(flatbuffers::ElementaryType elementary_type,
169 double double_value);
170 bool PushElement(flatbuffers::ElementaryType elementary_type,
171 flatbuffers::Offset<flatbuffers::String> offset_value);
172
173 flatbuffers::FlatBufferBuilder fbb_;
174
175 // This holds the state information that is needed as you recurse into
176 // nested structures.
177 struct FlatBufferContext {
178 // Type of the current type.
179 const flatbuffers::TypeTable *typetable;
180 // If true, we are parsing a vector.
181 bool in_vector;
182 // The field index of the current field.
183 int field_index;
184 // Name of the current field.
185 ::std::string field_name;
186
187 // Field elements that need to be inserted.
188 ::std::vector<FieldElement> elements;
189 };
190 ::std::vector<FlatBufferContext> stack_;
191
192 // For scalar types (not strings, and not nested tables), the vector ends
193 // up being implemented as a start and end, and a block of data. So we
194 // can't just push offsets in as we go. We either need to reproduce the
195 // logic inside flatbuffers, or build up vectors of the data. Vectors will
196 // be a bit of extra stack space, but whatever.
197 //
198 // Strings and nested structures are vectors of offsets.
199 // into the vector. Once you get to the end, you build up a vector and
200 // push that into the field.
201 ::std::vector<Element> vector_elements_;
202};
203
204bool JsonParser::DoParse(const flatbuffers::TypeTable *typetable,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700205 const absl::string_view data,
206 flatbuffers::uoffset_t *table_end) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700207 ::std::vector<const flatbuffers::TypeTable *> stack;
208
209 Tokenizer t(data);
210
211 // Main loop. Run until we get an end.
212 while (true) {
213 Tokenizer::TokenType token = t.Next();
214
215 switch (token) {
216 case Tokenizer::TokenType::kEnd:
217 if (stack_.size() != 0) {
218 printf("Failed to unwind stack all the way\n");
219 return false;
220 } else {
221 return true;
222 }
223 break;
224 case Tokenizer::TokenType::kError:
225 return false;
226 break;
227
228 case Tokenizer::TokenType::kStartObject: // {
229 if (stack_.size() == 0) {
230 stack_.push_back({typetable, false, -1, "", {}});
231 } else {
232 int field_index = stack_.back().field_index;
233
234 const flatbuffers::TypeCode &type_code =
235 stack_.back().typetable->type_codes[field_index];
236
237 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
238 printf("Field '%s' is not a sequence\n",
239 stack_.back().field_name.c_str());
240 return false;
241 }
242
243 flatbuffers::TypeFunction type_function =
244 stack_.back().typetable->type_refs[type_code.sequence_ref];
245
246 stack_.push_back({type_function(), false, -1, "", {}});
247 }
248 break;
249 case Tokenizer::TokenType::kEndObject: // }
250 if (stack_.size() == 0) {
251 // Somehow we popped more than we pushed. Error.
252 printf("Empty stack\n");
253 return false;
254 } else {
255 // End of a nested struct! Add it.
Austin Schuh43c6a352019-09-30 22:22:10 -0700256 const flatbuffers::uoffset_t end = WriteTable(
257 stack_.back().typetable, stack_.back().elements, &fbb_);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700258
259 // We now want to talk about the parent structure. Pop the child.
260 stack_.pop_back();
261
262 if (stack_.size() == 0) {
263 // Instead of queueing it up in the stack, return it through the
264 // passed in variable.
265 *table_end = end;
266 } else {
267 // And now we can add it.
268 const int field_index = stack_.back().field_index;
269
270 // Do the right thing if we are in a vector.
271 if (in_vector()) {
272 vector_elements_.emplace_back(
273 flatbuffers::Offset<flatbuffers::String>(end));
274 } else {
275 stack_.back().elements.emplace_back(
276 field_index, flatbuffers::Offset<flatbuffers::String>(end));
277 }
278 }
279 }
280 break;
281
282 case Tokenizer::TokenType::kStartArray: // [
283 if (stack_.size() == 0) {
284 // We don't support an array of structs at the root level.
285 return false;
286 }
287 // Sanity check that we aren't trying to make a vector of vectors.
288 if (in_vector()) {
289 return false;
290 }
291 set_in_vector(true);
292
293 break;
294 case Tokenizer::TokenType::kEndArray: { // ]
295 if (!in_vector()) {
296 return false;
297 }
298
299 const int field_index = stack_.back().field_index;
300
301 if (!FinishVector(field_index)) return false;
302
303 set_in_vector(false);
304 } break;
305
306 case Tokenizer::TokenType::kTrueValue: // true
307 case Tokenizer::TokenType::kFalseValue: // false
308 case Tokenizer::TokenType::kNumberValue: {
309 bool is_int = true;
310 double double_value;
311 long long int_value;
312 if (token == Tokenizer::TokenType::kTrueValue) {
313 int_value = 1;
314 } else if (token == Tokenizer::TokenType::kFalseValue) {
315 int_value = 0;
316 } else if (!t.FieldAsInt(&int_value)) {
317 if (t.FieldAsDouble(&double_value)) {
318 is_int = false;
319 } else {
320 fprintf(stderr, "Got a invalid number '%s'\n",
321 t.field_value().c_str());
322 return false;
323 }
324 }
325
326 const int field_index = stack_.back().field_index;
327
328 if (is_int) {
329 // No need to get too stressed about bool vs int. Convert them all.
330 int64_t val = int_value;
331 if (!AddElement(field_index, val)) return false;
332 } else {
333 if (!AddElement(field_index, double_value)) return false;
334 }
335 } break;
336 // TODO(austin): Need to detect int vs float.
337 /*
338 asdf
339 {
340 const int field_index = stack_.back().field_index;
341
342 } break;
343 */
344 case Tokenizer::TokenType::kStringValue: // string value
345 {
346 const int field_index = stack_.back().field_index;
347
348 if (!AddElement(field_index, t.field_value())) return false;
349 } break;
350 case Tokenizer::TokenType::kField: // field name
351 {
352 stack_.back().field_name = t.field_name();
353 stack_.back().field_index = FieldIndex(
354 stack_.back().typetable, stack_.back().field_name.c_str());
355
356 if (stack_.back().field_index == -1) {
357 printf("Invalid field name '%s'\n", stack_.back().field_name.c_str());
358 return false;
359 }
360 } break;
361 }
362 }
363 return false;
364}
365
366bool JsonParser::AddElement(int field_index, int64_t int_value) {
367 flatbuffers::TypeCode type_code =
368 stack_.back().typetable->type_codes[field_index];
369
370 if (type_code.is_vector != in_vector()) {
371 printf("Type and json disagree on if we are in a vector or not\n");
372 return false;
373 }
374
375 if (in_vector()) {
376 vector_elements_.emplace_back(int_value);
377 } else {
378 stack_.back().elements.emplace_back(field_index, int_value);
379 }
380 return true;
381}
382
383bool JsonParser::AddElement(int field_index, double double_value) {
384 flatbuffers::TypeCode type_code =
385 stack_.back().typetable->type_codes[field_index];
386
387 if (type_code.is_vector != in_vector()) {
388 printf("Type and json disagree on if we are in a vector or not\n");
389 return false;
390 }
391
392 if (in_vector()) {
393 vector_elements_.emplace_back(double_value);
394 } else {
395 stack_.back().elements.emplace_back(field_index, double_value);
396 }
397 return true;
398}
399
400bool JsonParser::AddElement(int field_index, const ::std::string &data) {
401 flatbuffers::TypeCode type_code =
402 stack_.back().typetable->type_codes[field_index];
403
404 if (type_code.is_vector != in_vector()) {
405 printf("Type and json disagree on if we are in a vector or not\n");
406 return false;
407 }
408
409 if (in_vector()) {
410 vector_elements_.emplace_back(fbb_.CreateString(data));
411
412 } else {
413 stack_.back().elements.emplace_back(field_index, fbb_.CreateString(data));
414 }
415 return true;
416}
417
Austin Schuh43c6a352019-09-30 22:22:10 -0700418bool AddSingleElement(const flatbuffers::TypeTable *typetable,
419 const FieldElement &field_element,
420 ::std::vector<bool> *fields_in_use,
421 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700422 if ((*fields_in_use)[field_element.field_index]) {
423 printf("Duplicate field: '%s'\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700424 typetable->names[field_element.field_index]);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700425 return false;
426 }
427
428 (*fields_in_use)[field_element.field_index] = true;
429
430 switch (field_element.element.type) {
431 case Element::ElementType::INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700432 return AddSingleElement(typetable, field_element.field_index,
433 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700434 case Element::ElementType::DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700435 return AddSingleElement(typetable, field_element.field_index,
436 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700437 case Element::ElementType::OFFSET:
Austin Schuh43c6a352019-09-30 22:22:10 -0700438 return AddSingleElement(typetable, field_element.field_index,
439 field_element.element.offset_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700440 }
441 return false;
442}
443
Austin Schuh43c6a352019-09-30 22:22:10 -0700444bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
445 int64_t int_value, flatbuffers::FlatBufferBuilder *fbb
446
447) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700448 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
449 static_cast<flatbuffers::voffset_t>(field_index));
450
Austin Schuh43c6a352019-09-30 22:22:10 -0700451 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700452
453 const flatbuffers::ElementaryType elementary_type =
454 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
455 switch (elementary_type) {
456 case flatbuffers::ET_BOOL:
Austin Schuh43c6a352019-09-30 22:22:10 -0700457 fbb->AddElement<bool>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700458 return true;
459 case flatbuffers::ET_CHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700460 fbb->AddElement<int8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700461 return true;
462 case flatbuffers::ET_UCHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700463 fbb->AddElement<uint8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700464 return true;
465 case flatbuffers::ET_SHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700466 fbb->AddElement<int16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700467 return true;
468 case flatbuffers::ET_USHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700469 fbb->AddElement<uint16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700470 return true;
471 case flatbuffers::ET_INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700472 fbb->AddElement<int32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700473 return true;
474 case flatbuffers::ET_UINT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700475 fbb->AddElement<uint32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700476 return true;
477 case flatbuffers::ET_LONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700478 fbb->AddElement<int64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700479 return true;
480 case flatbuffers::ET_ULONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700481 fbb->AddElement<uint64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700482 return true;
483 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700484 fbb->AddElement<float>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700485 return true;
486 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700487 fbb->AddElement<double>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700488 return true;
489 case flatbuffers::ET_STRING:
490 case flatbuffers::ET_UTYPE:
491 case flatbuffers::ET_SEQUENCE:
492 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700493 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700494 ElementaryTypeName(elementary_type));
495 return false;
496 };
497 return false;
498}
499
Austin Schuh43c6a352019-09-30 22:22:10 -0700500bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
501 double double_value,
502 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700503 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
504 static_cast<flatbuffers::voffset_t>(field_index));
505
Austin Schuh43c6a352019-09-30 22:22:10 -0700506 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700507
508 const flatbuffers::ElementaryType elementary_type =
509 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
510 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:
522 case flatbuffers::ET_SEQUENCE:
523 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700524 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700525 ElementaryTypeName(elementary_type));
526 return false;
527 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700528 fbb->AddElement<float>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700529 return true;
530 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700531 fbb->AddElement<double>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700532 return true;
533 }
534 return false;
535}
Austin Schuh43c6a352019-09-30 22:22:10 -0700536bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
537 flatbuffers::Offset<flatbuffers::String> offset_element,
538 flatbuffers::FlatBufferBuilder *fbb) {
539 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700540
541 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
542 static_cast<flatbuffers::voffset_t>(field_index));
543
544 // Vectors will always be Offset<>'s.
545 if (type_code.is_vector) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700546 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700547 return true;
548 }
549
550 const flatbuffers::ElementaryType elementary_type =
551 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
552 switch (elementary_type) {
553 case flatbuffers::ET_UTYPE:
554 case flatbuffers::ET_BOOL:
555 case flatbuffers::ET_CHAR:
556 case flatbuffers::ET_UCHAR:
557 case flatbuffers::ET_SHORT:
558 case flatbuffers::ET_USHORT:
559 case flatbuffers::ET_INT:
560 case flatbuffers::ET_UINT:
561 case flatbuffers::ET_LONG:
562 case flatbuffers::ET_ULONG:
563 case flatbuffers::ET_FLOAT:
564 case flatbuffers::ET_DOUBLE:
565 printf("Mismatched type for field '%s'. Got: string, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700566 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700567 ElementaryTypeName(elementary_type));
568 return false;
569 case flatbuffers::ET_SEQUENCE:
570 case flatbuffers::ET_STRING:
Austin Schuh43c6a352019-09-30 22:22:10 -0700571 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700572 return true;
573 }
574 return false;
575}
576
577bool JsonParser::FinishVector(int field_index) {
578 flatbuffers::TypeCode type_code =
579 stack_.back().typetable->type_codes[field_index];
580
581 const flatbuffers::ElementaryType elementary_type =
582 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
583
584 // Vectors have a start (unfortunately which needs to know the size)
585 fbb_.StartVector(
586 vector_elements_.size(),
587 flatbuffers::InlineSize(elementary_type, stack_.back().typetable));
588
589 // Then the data (in reverse order for some reason...)
590 for (size_t i = vector_elements_.size(); i > 0;) {
591 const Element &element = vector_elements_[--i];
592 switch (element.type) {
593 case Element::ElementType::INT:
594 if (!PushElement(elementary_type, element.int_element)) return false;
595 break;
596 case Element::ElementType::DOUBLE:
597 if (!PushElement(elementary_type, element.double_element)) return false;
598 break;
599 case Element::ElementType::OFFSET:
600 if (!PushElement(elementary_type, element.offset_element)) return false;
601 break;
602 }
603 }
604
605 // Then an End which is placed into the buffer the same as any other offset.
606 stack_.back().elements.emplace_back(
607 field_index, flatbuffers::Offset<flatbuffers::String>(
608 fbb_.EndVector(vector_elements_.size())));
609 return true;
610}
611
612bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
613 int64_t int_value) {
614 switch (elementary_type) {
615 case flatbuffers::ET_BOOL:
616 fbb_.PushElement<bool>(int_value);
617 return true;
618 case flatbuffers::ET_CHAR:
619 fbb_.PushElement<int8_t>(int_value);
620 return true;
621 case flatbuffers::ET_UCHAR:
622 fbb_.PushElement<uint8_t>(int_value);
623 return true;
624 case flatbuffers::ET_SHORT:
625 fbb_.PushElement<int16_t>(int_value);
626 return true;
627 case flatbuffers::ET_USHORT:
628 fbb_.PushElement<uint16_t>(int_value);
629 return true;
630 case flatbuffers::ET_INT:
631 fbb_.PushElement<int32_t>(int_value);
632 return true;
633 case flatbuffers::ET_UINT:
634 fbb_.PushElement<uint32_t>(int_value);
635 return true;
636 case flatbuffers::ET_LONG:
637 fbb_.PushElement<int64_t>(int_value);
638 return true;
639 case flatbuffers::ET_ULONG:
640 fbb_.PushElement<uint64_t>(int_value);
641 return true;
642 case flatbuffers::ET_FLOAT:
643 fbb_.PushElement<float>(int_value);
644 return true;
645 case flatbuffers::ET_DOUBLE:
646 fbb_.PushElement<double>(int_value);
647 return true;
648 case flatbuffers::ET_STRING:
649 case flatbuffers::ET_UTYPE:
650 case flatbuffers::ET_SEQUENCE:
651 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
652 stack_.back().field_name.c_str(),
653 ElementaryTypeName(elementary_type));
654 return false;
655 };
656 return false;
657}
658
659bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
660 double double_value) {
661 switch (elementary_type) {
662 case flatbuffers::ET_UTYPE:
663 case flatbuffers::ET_BOOL:
664 case flatbuffers::ET_CHAR:
665 case flatbuffers::ET_UCHAR:
666 case flatbuffers::ET_SHORT:
667 case flatbuffers::ET_USHORT:
668 case flatbuffers::ET_INT:
669 case flatbuffers::ET_UINT:
670 case flatbuffers::ET_LONG:
671 case flatbuffers::ET_ULONG:
672 case flatbuffers::ET_STRING:
673 case flatbuffers::ET_SEQUENCE:
674 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
675 stack_.back().field_name.c_str(),
676 ElementaryTypeName(elementary_type));
677 return false;
678 case flatbuffers::ET_FLOAT:
679 fbb_.PushElement<float>(double_value);
680 return true;
681 case flatbuffers::ET_DOUBLE:
682 fbb_.PushElement<double>(double_value);
683 return true;
684 }
685 return false;
686}
687
688bool JsonParser::PushElement(
689 flatbuffers::ElementaryType elementary_type,
690 flatbuffers::Offset<flatbuffers::String> offset_value) {
691 switch (elementary_type) {
692 case flatbuffers::ET_UTYPE:
693 case flatbuffers::ET_BOOL:
694 case flatbuffers::ET_CHAR:
695 case flatbuffers::ET_UCHAR:
696 case flatbuffers::ET_SHORT:
697 case flatbuffers::ET_USHORT:
698 case flatbuffers::ET_INT:
699 case flatbuffers::ET_UINT:
700 case flatbuffers::ET_LONG:
701 case flatbuffers::ET_ULONG:
702 case flatbuffers::ET_FLOAT:
703 case flatbuffers::ET_DOUBLE:
704 printf("Mismatched type for field '%s'. Got: sequence, expected %s\n",
705 stack_.back().field_name.c_str(),
706 ElementaryTypeName(elementary_type));
707 return false;
708 case flatbuffers::ET_STRING:
709 case flatbuffers::ET_SEQUENCE:
710 fbb_.PushElement(offset_value);
711 return true;
712 }
713 return false;
714}
715
716} // namespace
717
718::std::vector<uint8_t> JsonToFlatbuffer(
Austin Schuhd339a9b2019-10-05 21:33:32 -0700719 const absl::string_view data, const flatbuffers::TypeTable *typetable) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700720 JsonParser p;
721 return p.Parse(data, typetable);
722}
723
724::std::string FlatbufferToJson(const uint8_t *buffer,
725 const ::flatbuffers::TypeTable *typetable,
726 bool multi_line) {
727 ::flatbuffers::ToStringVisitor tostring_visitor(
728 multi_line ? "\n" : " ", true, multi_line ? " " : "", multi_line);
729 IterateFlatBuffer(buffer, typetable, &tostring_visitor);
730 return tostring_visitor.s;
731}
732
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700733} // namespace aos