blob: 939dca76ef9115fdda4519a66bed5817be38878b [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;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700336 case Tokenizer::TokenType::kStringValue: // string value
337 {
338 const int field_index = stack_.back().field_index;
339
340 if (!AddElement(field_index, t.field_value())) return false;
341 } break;
342 case Tokenizer::TokenType::kField: // field name
343 {
344 stack_.back().field_name = t.field_name();
345 stack_.back().field_index = FieldIndex(
346 stack_.back().typetable, stack_.back().field_name.c_str());
347
348 if (stack_.back().field_index == -1) {
349 printf("Invalid field name '%s'\n", stack_.back().field_name.c_str());
350 return false;
351 }
352 } break;
353 }
354 }
355 return false;
356}
357
358bool JsonParser::AddElement(int field_index, int64_t int_value) {
359 flatbuffers::TypeCode type_code =
360 stack_.back().typetable->type_codes[field_index];
361
362 if (type_code.is_vector != in_vector()) {
363 printf("Type and json disagree on if we are in a vector or not\n");
364 return false;
365 }
366
367 if (in_vector()) {
368 vector_elements_.emplace_back(int_value);
369 } else {
370 stack_.back().elements.emplace_back(field_index, int_value);
371 }
372 return true;
373}
374
375bool JsonParser::AddElement(int field_index, double double_value) {
376 flatbuffers::TypeCode type_code =
377 stack_.back().typetable->type_codes[field_index];
378
379 if (type_code.is_vector != in_vector()) {
380 printf("Type and json disagree on if we are in a vector or not\n");
381 return false;
382 }
383
384 if (in_vector()) {
385 vector_elements_.emplace_back(double_value);
386 } else {
387 stack_.back().elements.emplace_back(field_index, double_value);
388 }
389 return true;
390}
391
392bool JsonParser::AddElement(int field_index, const ::std::string &data) {
393 flatbuffers::TypeCode type_code =
394 stack_.back().typetable->type_codes[field_index];
395
396 if (type_code.is_vector != in_vector()) {
397 printf("Type and json disagree on if we are in a vector or not\n");
398 return false;
399 }
400
401 if (in_vector()) {
402 vector_elements_.emplace_back(fbb_.CreateString(data));
403
404 } else {
405 stack_.back().elements.emplace_back(field_index, fbb_.CreateString(data));
406 }
407 return true;
408}
409
Austin Schuh43c6a352019-09-30 22:22:10 -0700410bool AddSingleElement(const flatbuffers::TypeTable *typetable,
411 const FieldElement &field_element,
412 ::std::vector<bool> *fields_in_use,
413 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700414 if ((*fields_in_use)[field_element.field_index]) {
415 printf("Duplicate field: '%s'\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700416 typetable->names[field_element.field_index]);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700417 return false;
418 }
419
420 (*fields_in_use)[field_element.field_index] = true;
421
422 switch (field_element.element.type) {
423 case Element::ElementType::INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700424 return AddSingleElement(typetable, field_element.field_index,
425 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700426 case Element::ElementType::DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700427 return AddSingleElement(typetable, field_element.field_index,
428 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700429 case Element::ElementType::OFFSET:
Austin Schuh43c6a352019-09-30 22:22:10 -0700430 return AddSingleElement(typetable, field_element.field_index,
431 field_element.element.offset_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700432 }
433 return false;
434}
435
Austin Schuh43c6a352019-09-30 22:22:10 -0700436bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
437 int64_t int_value, flatbuffers::FlatBufferBuilder *fbb
438
439) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700440 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
441 static_cast<flatbuffers::voffset_t>(field_index));
442
Austin Schuh43c6a352019-09-30 22:22:10 -0700443 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700444
445 const flatbuffers::ElementaryType elementary_type =
446 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
447 switch (elementary_type) {
448 case flatbuffers::ET_BOOL:
Austin Schuh43c6a352019-09-30 22:22:10 -0700449 fbb->AddElement<bool>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700450 return true;
451 case flatbuffers::ET_CHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700452 fbb->AddElement<int8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700453 return true;
454 case flatbuffers::ET_UCHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700455 fbb->AddElement<uint8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700456 return true;
457 case flatbuffers::ET_SHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700458 fbb->AddElement<int16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700459 return true;
460 case flatbuffers::ET_USHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700461 fbb->AddElement<uint16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700462 return true;
463 case flatbuffers::ET_INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700464 fbb->AddElement<int32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700465 return true;
466 case flatbuffers::ET_UINT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700467 fbb->AddElement<uint32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700468 return true;
469 case flatbuffers::ET_LONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700470 fbb->AddElement<int64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700471 return true;
472 case flatbuffers::ET_ULONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700473 fbb->AddElement<uint64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700474 return true;
475 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700476 fbb->AddElement<float>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700477 return true;
478 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700479 fbb->AddElement<double>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700480 return true;
481 case flatbuffers::ET_STRING:
482 case flatbuffers::ET_UTYPE:
483 case flatbuffers::ET_SEQUENCE:
484 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700485 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700486 ElementaryTypeName(elementary_type));
487 return false;
488 };
489 return false;
490}
491
Austin Schuh43c6a352019-09-30 22:22:10 -0700492bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
493 double double_value,
494 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700495 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
496 static_cast<flatbuffers::voffset_t>(field_index));
497
Austin Schuh43c6a352019-09-30 22:22:10 -0700498 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700499
500 const flatbuffers::ElementaryType elementary_type =
501 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
502 switch (elementary_type) {
503 case flatbuffers::ET_UTYPE:
504 case flatbuffers::ET_BOOL:
505 case flatbuffers::ET_CHAR:
506 case flatbuffers::ET_UCHAR:
507 case flatbuffers::ET_SHORT:
508 case flatbuffers::ET_USHORT:
509 case flatbuffers::ET_INT:
510 case flatbuffers::ET_UINT:
511 case flatbuffers::ET_LONG:
512 case flatbuffers::ET_ULONG:
513 case flatbuffers::ET_STRING:
514 case flatbuffers::ET_SEQUENCE:
515 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700516 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700517 ElementaryTypeName(elementary_type));
518 return false;
519 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700520 fbb->AddElement<float>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700521 return true;
522 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700523 fbb->AddElement<double>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700524 return true;
525 }
526 return false;
527}
Austin Schuh43c6a352019-09-30 22:22:10 -0700528bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
529 flatbuffers::Offset<flatbuffers::String> offset_element,
530 flatbuffers::FlatBufferBuilder *fbb) {
531 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700532
533 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
534 static_cast<flatbuffers::voffset_t>(field_index));
535
536 // Vectors will always be Offset<>'s.
537 if (type_code.is_vector) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700538 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700539 return true;
540 }
541
542 const flatbuffers::ElementaryType elementary_type =
543 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
544 switch (elementary_type) {
545 case flatbuffers::ET_UTYPE:
546 case flatbuffers::ET_BOOL:
547 case flatbuffers::ET_CHAR:
548 case flatbuffers::ET_UCHAR:
549 case flatbuffers::ET_SHORT:
550 case flatbuffers::ET_USHORT:
551 case flatbuffers::ET_INT:
552 case flatbuffers::ET_UINT:
553 case flatbuffers::ET_LONG:
554 case flatbuffers::ET_ULONG:
555 case flatbuffers::ET_FLOAT:
556 case flatbuffers::ET_DOUBLE:
557 printf("Mismatched type for field '%s'. Got: string, expected %s\n",
Austin Schuh43c6a352019-09-30 22:22:10 -0700558 typetable->names[field_index],
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700559 ElementaryTypeName(elementary_type));
560 return false;
561 case flatbuffers::ET_SEQUENCE:
562 case flatbuffers::ET_STRING:
Austin Schuh43c6a352019-09-30 22:22:10 -0700563 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700564 return true;
565 }
566 return false;
567}
568
569bool JsonParser::FinishVector(int field_index) {
570 flatbuffers::TypeCode type_code =
571 stack_.back().typetable->type_codes[field_index];
572
573 const flatbuffers::ElementaryType elementary_type =
574 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
575
576 // Vectors have a start (unfortunately which needs to know the size)
577 fbb_.StartVector(
578 vector_elements_.size(),
579 flatbuffers::InlineSize(elementary_type, stack_.back().typetable));
580
581 // Then the data (in reverse order for some reason...)
582 for (size_t i = vector_elements_.size(); i > 0;) {
583 const Element &element = vector_elements_[--i];
584 switch (element.type) {
585 case Element::ElementType::INT:
586 if (!PushElement(elementary_type, element.int_element)) return false;
587 break;
588 case Element::ElementType::DOUBLE:
589 if (!PushElement(elementary_type, element.double_element)) return false;
590 break;
591 case Element::ElementType::OFFSET:
592 if (!PushElement(elementary_type, element.offset_element)) return false;
593 break;
594 }
595 }
596
597 // Then an End which is placed into the buffer the same as any other offset.
598 stack_.back().elements.emplace_back(
599 field_index, flatbuffers::Offset<flatbuffers::String>(
600 fbb_.EndVector(vector_elements_.size())));
Austin Schuh9e2532d2019-10-06 14:01:15 -0700601 vector_elements_.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700602 return true;
603}
604
605bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
606 int64_t int_value) {
607 switch (elementary_type) {
608 case flatbuffers::ET_BOOL:
609 fbb_.PushElement<bool>(int_value);
610 return true;
611 case flatbuffers::ET_CHAR:
612 fbb_.PushElement<int8_t>(int_value);
613 return true;
614 case flatbuffers::ET_UCHAR:
615 fbb_.PushElement<uint8_t>(int_value);
616 return true;
617 case flatbuffers::ET_SHORT:
618 fbb_.PushElement<int16_t>(int_value);
619 return true;
620 case flatbuffers::ET_USHORT:
621 fbb_.PushElement<uint16_t>(int_value);
622 return true;
623 case flatbuffers::ET_INT:
624 fbb_.PushElement<int32_t>(int_value);
625 return true;
626 case flatbuffers::ET_UINT:
627 fbb_.PushElement<uint32_t>(int_value);
628 return true;
629 case flatbuffers::ET_LONG:
630 fbb_.PushElement<int64_t>(int_value);
631 return true;
632 case flatbuffers::ET_ULONG:
633 fbb_.PushElement<uint64_t>(int_value);
634 return true;
635 case flatbuffers::ET_FLOAT:
636 fbb_.PushElement<float>(int_value);
637 return true;
638 case flatbuffers::ET_DOUBLE:
639 fbb_.PushElement<double>(int_value);
640 return true;
641 case flatbuffers::ET_STRING:
642 case flatbuffers::ET_UTYPE:
643 case flatbuffers::ET_SEQUENCE:
644 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
645 stack_.back().field_name.c_str(),
646 ElementaryTypeName(elementary_type));
647 return false;
648 };
649 return false;
650}
651
652bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
653 double double_value) {
654 switch (elementary_type) {
655 case flatbuffers::ET_UTYPE:
656 case flatbuffers::ET_BOOL:
657 case flatbuffers::ET_CHAR:
658 case flatbuffers::ET_UCHAR:
659 case flatbuffers::ET_SHORT:
660 case flatbuffers::ET_USHORT:
661 case flatbuffers::ET_INT:
662 case flatbuffers::ET_UINT:
663 case flatbuffers::ET_LONG:
664 case flatbuffers::ET_ULONG:
665 case flatbuffers::ET_STRING:
666 case flatbuffers::ET_SEQUENCE:
667 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
668 stack_.back().field_name.c_str(),
669 ElementaryTypeName(elementary_type));
670 return false;
671 case flatbuffers::ET_FLOAT:
672 fbb_.PushElement<float>(double_value);
673 return true;
674 case flatbuffers::ET_DOUBLE:
675 fbb_.PushElement<double>(double_value);
676 return true;
677 }
678 return false;
679}
680
681bool JsonParser::PushElement(
682 flatbuffers::ElementaryType elementary_type,
683 flatbuffers::Offset<flatbuffers::String> offset_value) {
684 switch (elementary_type) {
685 case flatbuffers::ET_UTYPE:
686 case flatbuffers::ET_BOOL:
687 case flatbuffers::ET_CHAR:
688 case flatbuffers::ET_UCHAR:
689 case flatbuffers::ET_SHORT:
690 case flatbuffers::ET_USHORT:
691 case flatbuffers::ET_INT:
692 case flatbuffers::ET_UINT:
693 case flatbuffers::ET_LONG:
694 case flatbuffers::ET_ULONG:
695 case flatbuffers::ET_FLOAT:
696 case flatbuffers::ET_DOUBLE:
697 printf("Mismatched type for field '%s'. Got: sequence, expected %s\n",
698 stack_.back().field_name.c_str(),
699 ElementaryTypeName(elementary_type));
700 return false;
701 case flatbuffers::ET_STRING:
702 case flatbuffers::ET_SEQUENCE:
703 fbb_.PushElement(offset_value);
704 return true;
705 }
706 return false;
707}
708
709} // namespace
710
711::std::vector<uint8_t> JsonToFlatbuffer(
Austin Schuhd339a9b2019-10-05 21:33:32 -0700712 const absl::string_view data, const flatbuffers::TypeTable *typetable) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700713 JsonParser p;
714 return p.Parse(data, typetable);
715}
716
717::std::string FlatbufferToJson(const uint8_t *buffer,
718 const ::flatbuffers::TypeTable *typetable,
719 bool multi_line) {
720 ::flatbuffers::ToStringVisitor tostring_visitor(
721 multi_line ? "\n" : " ", true, multi_line ? " " : "", multi_line);
722 IterateFlatBuffer(buffer, typetable, &tostring_visitor);
723 return tostring_visitor.s;
724}
725
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700726} // namespace aos