blob: 737bacb2574672acde8859c5c66b358803f22d23 [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
6#include "aos/logging/logging.h"
7#include "flatbuffers/flatbuffers.h"
8#include "flatbuffers/minireflect.h"
9
10// TODO(austin): Can we just do an Offset<void> ? It doesn't matter, so maybe
11// just say that.
12//
13// TODO(austin): I've yet to see how to create an ET_UTYPE, so I don't know what
14// one is and how to test it. So everything rejects it.
15
16namespace aos {
17
18// Finds the field index in the table given the name.
19int FieldIndex(const flatbuffers::TypeTable *typetable,
20 const char *field_name) {
21 CHECK(typetable->values == nullptr);
22 for (size_t i = 0; i < typetable->num_elems; ++i) {
23 if (strcmp(field_name, typetable->names[i]) == 0) {
24 return i;
25 }
26 }
27 return -1;
28}
29
30namespace {
31
32// Class to hold one of the 3 json types for an array.
33struct Element {
34 // The type.
35 enum class ElementType { INT, DOUBLE, OFFSET };
36
37 // Constructs an Element holding an integer.
38 Element(int64_t new_int_element)
39 : int_element(new_int_element), type(ElementType::INT) {}
40 // Constructs an Element holding an double.
41 Element(double new_double_element)
42 : double_element(new_double_element), type(ElementType::DOUBLE) {}
43 // Constructs an Element holding an Offset.
44 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
45 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
46
47 // Union for the various datatypes.
48 union {
49 int64_t int_element;
50 double double_element;
51 flatbuffers::Offset<flatbuffers::String> offset_element;
52 };
53
54 // And an enum signaling which one is in use.
55 ElementType type;
56};
57
58// Structure to represent a field element.
59struct FieldElement {
60 FieldElement(int new_field_index, int64_t int_element)
61 : element(int_element), field_index(new_field_index) {}
62 FieldElement(int new_field_index, double double_element)
63 : element(double_element), field_index(new_field_index) {}
64 FieldElement(int new_field_index,
65 flatbuffers::Offset<flatbuffers::String> offset_element)
66 : element(offset_element), field_index(new_field_index) {}
67
68 // Data to write.
69 Element element;
70 // Field index. The type table which this index is for is stored outside this
71 // object.
72 int field_index;
73};
74
75// Class to parse JSON into a flatbuffer.
76//
77// The basic strategy is that we need to do everything backwards. So we need to
78// build up what we need to do fully in memory, then do it.
79//
80// The driver for this is that strings need to be fully created before the
81// tables that use them. Same for sub messages. But, we only know we have them
82// all when the structure ends. So, store each sub message in a FieldElement
83// and put them in the table at the end when we finish up each message. Same
84// goes for vectors.
85class JsonParser {
86 public:
87 JsonParser() { fbb_.ForceDefaults(1); }
88 ~JsonParser() {}
89
90 // Parses the json into a flatbuffer. Returns either an empty vector on
91 // error, or a vector with the flatbuffer data in it.
92 ::std::vector<uint8_t> Parse(const char *data,
93 const flatbuffers::TypeTable *typetable) {
94 flatbuffers::uoffset_t end;
95 bool result = DoParse(typetable, data, &end);
96
97 if (result) {
98 // On success, finish the table and build the vector.
99 auto o = flatbuffers::Offset<flatbuffers::Table>(end);
100 fbb_.Finish(o);
101
102 const uint8_t *buf = fbb_.GetBufferPointer();
103 const int size = fbb_.GetSize();
104 return ::std::vector<uint8_t>(buf, buf + size);
105 } else {
106 // Otherwise return an empty vector.
107 return ::std::vector<uint8_t>();
108 }
109 }
110
111 private:
112 // Setters and getters for in_vector (at the current level of the stack)
113 bool in_vector() const { return stack_.back().in_vector; }
114 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
115
116 // Parses the flatbuffer. This is a second method so we can do easier
117 // cleanup at the top level. Returns true on success.
118 bool DoParse(const flatbuffers::TypeTable *typetable, const char *data,
119 flatbuffers::uoffset_t *table_end);
120
121 // Adds *_value for the provided field. If we are in a vector, queues the
122 // data up in vector_elements_. Returns true on success.
123 bool AddElement(int field_index, int64_t int_value);
124 bool AddElement(int field_index, double double_value);
125 bool AddElement(int field_index, const ::std::string &data);
126
127 // Adds a single element. This assumes that vectors have been dealt with
128 // already. Returns true on success.
129 bool AddSingleElement(const FieldElement &field_element,
130 ::std::vector<bool> *fields_in_use);
131 bool AddSingleElement(int field_index, int64_t int_value);
132 bool AddSingleElement(int field_index, double double_value);
133 bool AddSingleElement(
134 int field_index, flatbuffers::Offset<flatbuffers::String> offset_element);
135
136 const char *ElementaryTypeName(
137 const flatbuffers::ElementaryType elementary_type) {
138 return flatbuffers::ElementaryTypeNames()[elementary_type] + 3;
139 }
140
141 // 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
152 flatbuffers::FlatBufferBuilder fbb_;
153
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.
158 const flatbuffers::TypeTable *typetable;
159 // 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;
168 };
169 ::std::vector<FlatBufferContext> stack_;
170
171 // For scalar types (not strings, and not nested tables), the vector ends
172 // up being implemented as a start and end, and a block of data. So we
173 // can't just push offsets in as we go. We either need to reproduce the
174 // logic inside flatbuffers, or build up vectors of the data. Vectors will
175 // be a bit of extra stack space, but whatever.
176 //
177 // Strings and nested structures are vectors of offsets.
178 // into the vector. Once you get to the end, you build up a vector and
179 // push that into the field.
180 ::std::vector<Element> vector_elements_;
181};
182
183bool JsonParser::DoParse(const flatbuffers::TypeTable *typetable,
184 const char *data, flatbuffers::uoffset_t *table_end) {
185 ::std::vector<const flatbuffers::TypeTable *> stack;
186
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) {
196 printf("Failed to unwind stack all the way\n");
197 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) {
208 stack_.push_back({typetable, false, -1, "", {}});
209 } else {
210 int field_index = stack_.back().field_index;
211
212 const flatbuffers::TypeCode &type_code =
213 stack_.back().typetable->type_codes[field_index];
214
215 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
216 printf("Field '%s' is not a sequence\n",
217 stack_.back().field_name.c_str());
218 return false;
219 }
220
221 flatbuffers::TypeFunction type_function =
222 stack_.back().typetable->type_refs[type_code.sequence_ref];
223
224 stack_.push_back({type_function(), false, -1, "", {}});
225 }
226 break;
227 case Tokenizer::TokenType::kEndObject: // }
228 if (stack_.size() == 0) {
229 // Somehow we popped more than we pushed. Error.
230 printf("Empty stack\n");
231 return false;
232 } else {
233 // End of a nested struct! Add it.
234 const flatbuffers::uoffset_t start = fbb_.StartTable();
235
236 ::std::vector<bool> fields_in_use(stack_.back().typetable->num_elems,
237 false);
238
239 for (const FieldElement &field_element : stack_.back().elements) {
240 AddSingleElement(field_element, &fields_in_use);
241 }
242
243 const flatbuffers::uoffset_t end = fbb_.EndTable(start);
244
245 // We now want to talk about the parent structure. Pop the child.
246 stack_.pop_back();
247
248 if (stack_.size() == 0) {
249 // Instead of queueing it up in the stack, return it through the
250 // passed in variable.
251 *table_end = end;
252 } else {
253 // And now we can add it.
254 const int field_index = stack_.back().field_index;
255
256 // Do the right thing if we are in a vector.
257 if (in_vector()) {
258 vector_elements_.emplace_back(
259 flatbuffers::Offset<flatbuffers::String>(end));
260 } else {
261 stack_.back().elements.emplace_back(
262 field_index, flatbuffers::Offset<flatbuffers::String>(end));
263 }
264 }
265 }
266 break;
267
268 case Tokenizer::TokenType::kStartArray: // [
269 if (stack_.size() == 0) {
270 // We don't support an array of structs at the root level.
271 return false;
272 }
273 // Sanity check that we aren't trying to make a vector of vectors.
274 if (in_vector()) {
275 return false;
276 }
277 set_in_vector(true);
278
279 break;
280 case Tokenizer::TokenType::kEndArray: { // ]
281 if (!in_vector()) {
282 return false;
283 }
284
285 const int field_index = stack_.back().field_index;
286
287 if (!FinishVector(field_index)) return false;
288
289 set_in_vector(false);
290 } break;
291
292 case Tokenizer::TokenType::kTrueValue: // true
293 case Tokenizer::TokenType::kFalseValue: // false
294 case Tokenizer::TokenType::kNumberValue: {
295 bool is_int = true;
296 double double_value;
297 long long int_value;
298 if (token == Tokenizer::TokenType::kTrueValue) {
299 int_value = 1;
300 } else if (token == Tokenizer::TokenType::kFalseValue) {
301 int_value = 0;
302 } else if (!t.FieldAsInt(&int_value)) {
303 if (t.FieldAsDouble(&double_value)) {
304 is_int = false;
305 } else {
306 fprintf(stderr, "Got a invalid number '%s'\n",
307 t.field_value().c_str());
308 return false;
309 }
310 }
311
312 const int field_index = stack_.back().field_index;
313
314 if (is_int) {
315 // No need to get too stressed about bool vs int. Convert them all.
316 int64_t val = int_value;
317 if (!AddElement(field_index, val)) return false;
318 } else {
319 if (!AddElement(field_index, double_value)) return false;
320 }
321 } break;
322 // TODO(austin): Need to detect int vs float.
323 /*
324 asdf
325 {
326 const int field_index = stack_.back().field_index;
327
328 } break;
329 */
330 case Tokenizer::TokenType::kStringValue: // string value
331 {
332 const int field_index = stack_.back().field_index;
333
334 if (!AddElement(field_index, t.field_value())) return false;
335 } break;
336 case Tokenizer::TokenType::kField: // field name
337 {
338 stack_.back().field_name = t.field_name();
339 stack_.back().field_index = FieldIndex(
340 stack_.back().typetable, stack_.back().field_name.c_str());
341
342 if (stack_.back().field_index == -1) {
343 printf("Invalid field name '%s'\n", stack_.back().field_name.c_str());
344 return false;
345 }
346 } break;
347 }
348 }
349 return false;
350}
351
352bool JsonParser::AddElement(int field_index, int64_t int_value) {
353 flatbuffers::TypeCode type_code =
354 stack_.back().typetable->type_codes[field_index];
355
356 if (type_code.is_vector != in_vector()) {
357 printf("Type and json disagree on if we are in a vector or not\n");
358 return false;
359 }
360
361 if (in_vector()) {
362 vector_elements_.emplace_back(int_value);
363 } else {
364 stack_.back().elements.emplace_back(field_index, int_value);
365 }
366 return true;
367}
368
369bool JsonParser::AddElement(int field_index, double double_value) {
370 flatbuffers::TypeCode type_code =
371 stack_.back().typetable->type_codes[field_index];
372
373 if (type_code.is_vector != in_vector()) {
374 printf("Type and json disagree on if we are in a vector or not\n");
375 return false;
376 }
377
378 if (in_vector()) {
379 vector_elements_.emplace_back(double_value);
380 } else {
381 stack_.back().elements.emplace_back(field_index, double_value);
382 }
383 return true;
384}
385
386bool JsonParser::AddElement(int field_index, const ::std::string &data) {
387 flatbuffers::TypeCode type_code =
388 stack_.back().typetable->type_codes[field_index];
389
390 if (type_code.is_vector != in_vector()) {
391 printf("Type and json disagree on if we are in a vector or not\n");
392 return false;
393 }
394
395 if (in_vector()) {
396 vector_elements_.emplace_back(fbb_.CreateString(data));
397
398 } else {
399 stack_.back().elements.emplace_back(field_index, fbb_.CreateString(data));
400 }
401 return true;
402}
403
404bool JsonParser::AddSingleElement(const FieldElement &field_element,
405 ::std::vector<bool> *fields_in_use) {
406 if ((*fields_in_use)[field_element.field_index]) {
407 printf("Duplicate field: '%s'\n",
408 stack_.back().typetable->names[field_element.field_index]);
409 return false;
410 }
411
412 (*fields_in_use)[field_element.field_index] = true;
413
414 switch (field_element.element.type) {
415 case Element::ElementType::INT:
416 return AddSingleElement(field_element.field_index,
417 field_element.element.int_element);
418 case Element::ElementType::DOUBLE:
419 return AddSingleElement(field_element.field_index,
420 field_element.element.double_element);
421 case Element::ElementType::OFFSET:
422 return AddSingleElement(field_element.field_index,
423 field_element.element.offset_element);
424 }
425 return false;
426}
427
428bool JsonParser::AddSingleElement(int field_index, int64_t int_value) {
429 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
430 static_cast<flatbuffers::voffset_t>(field_index));
431
432 flatbuffers::TypeCode type_code =
433 stack_.back().typetable->type_codes[field_index];
434
435 const flatbuffers::ElementaryType elementary_type =
436 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
437 switch (elementary_type) {
438 case flatbuffers::ET_BOOL:
439 fbb_.AddElement<bool>(field_offset, int_value, 0);
440 return true;
441 case flatbuffers::ET_CHAR:
442 fbb_.AddElement<int8_t>(field_offset, int_value, 0);
443 return true;
444 case flatbuffers::ET_UCHAR:
445 fbb_.AddElement<uint8_t>(field_offset, int_value, 0);
446 return true;
447 case flatbuffers::ET_SHORT:
448 fbb_.AddElement<int16_t>(field_offset, int_value, 0);
449 return true;
450 case flatbuffers::ET_USHORT:
451 fbb_.AddElement<uint16_t>(field_offset, int_value, 0);
452 return true;
453 case flatbuffers::ET_INT:
454 fbb_.AddElement<int32_t>(field_offset, int_value, 0);
455 return true;
456 case flatbuffers::ET_UINT:
457 fbb_.AddElement<uint32_t>(field_offset, int_value, 0);
458 return true;
459 case flatbuffers::ET_LONG:
460 fbb_.AddElement<int64_t>(field_offset, int_value, 0);
461 return true;
462 case flatbuffers::ET_ULONG:
463 fbb_.AddElement<uint64_t>(field_offset, int_value, 0);
464 return true;
465 case flatbuffers::ET_FLOAT:
466 fbb_.AddElement<float>(field_offset, int_value, 0);
467 return true;
468 case flatbuffers::ET_DOUBLE:
469 fbb_.AddElement<double>(field_offset, int_value, 0);
470 return true;
471 case flatbuffers::ET_STRING:
472 case flatbuffers::ET_UTYPE:
473 case flatbuffers::ET_SEQUENCE:
474 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
475 stack_.back().field_name.c_str(),
476 ElementaryTypeName(elementary_type));
477 return false;
478 };
479 return false;
480}
481
482bool JsonParser::AddSingleElement(int field_index, double double_value) {
483 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
484 static_cast<flatbuffers::voffset_t>(field_index));
485
486 flatbuffers::TypeCode type_code =
487 stack_.back().typetable->type_codes[field_index];
488
489 const flatbuffers::ElementaryType elementary_type =
490 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
491 switch (elementary_type) {
492 case flatbuffers::ET_UTYPE:
493 case flatbuffers::ET_BOOL:
494 case flatbuffers::ET_CHAR:
495 case flatbuffers::ET_UCHAR:
496 case flatbuffers::ET_SHORT:
497 case flatbuffers::ET_USHORT:
498 case flatbuffers::ET_INT:
499 case flatbuffers::ET_UINT:
500 case flatbuffers::ET_LONG:
501 case flatbuffers::ET_ULONG:
502 case flatbuffers::ET_STRING:
503 case flatbuffers::ET_SEQUENCE:
504 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
505 stack_.back().field_name.c_str(),
506 ElementaryTypeName(elementary_type));
507 return false;
508 case flatbuffers::ET_FLOAT:
509 fbb_.AddElement<float>(field_offset, double_value, 0);
510 return true;
511 case flatbuffers::ET_DOUBLE:
512 fbb_.AddElement<double>(field_offset, double_value, 0);
513 return true;
514 }
515 return false;
516}
517bool JsonParser::AddSingleElement(
518 int field_index, flatbuffers::Offset<flatbuffers::String> offset_element) {
519 flatbuffers::TypeCode type_code =
520 stack_.back().typetable->type_codes[field_index];
521
522 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
523 static_cast<flatbuffers::voffset_t>(field_index));
524
525 // Vectors will always be Offset<>'s.
526 if (type_code.is_vector) {
527 fbb_.AddOffset(field_offset, offset_element);
528 return true;
529 }
530
531 const flatbuffers::ElementaryType elementary_type =
532 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
533 switch (elementary_type) {
534 case flatbuffers::ET_UTYPE:
535 case flatbuffers::ET_BOOL:
536 case flatbuffers::ET_CHAR:
537 case flatbuffers::ET_UCHAR:
538 case flatbuffers::ET_SHORT:
539 case flatbuffers::ET_USHORT:
540 case flatbuffers::ET_INT:
541 case flatbuffers::ET_UINT:
542 case flatbuffers::ET_LONG:
543 case flatbuffers::ET_ULONG:
544 case flatbuffers::ET_FLOAT:
545 case flatbuffers::ET_DOUBLE:
546 printf("Mismatched type for field '%s'. Got: string, expected %s\n",
547 stack_.back().field_name.c_str(),
548 ElementaryTypeName(elementary_type));
549 return false;
550 case flatbuffers::ET_SEQUENCE:
551 case flatbuffers::ET_STRING:
552 fbb_.AddOffset(field_offset, offset_element);
553 return true;
554 }
555 return false;
556}
557
558bool JsonParser::FinishVector(int field_index) {
559 flatbuffers::TypeCode type_code =
560 stack_.back().typetable->type_codes[field_index];
561
562 const flatbuffers::ElementaryType elementary_type =
563 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
564
565 // Vectors have a start (unfortunately which needs to know the size)
566 fbb_.StartVector(
567 vector_elements_.size(),
568 flatbuffers::InlineSize(elementary_type, stack_.back().typetable));
569
570 // Then the data (in reverse order for some reason...)
571 for (size_t i = vector_elements_.size(); i > 0;) {
572 const Element &element = vector_elements_[--i];
573 switch (element.type) {
574 case Element::ElementType::INT:
575 if (!PushElement(elementary_type, element.int_element)) return false;
576 break;
577 case Element::ElementType::DOUBLE:
578 if (!PushElement(elementary_type, element.double_element)) return false;
579 break;
580 case Element::ElementType::OFFSET:
581 if (!PushElement(elementary_type, element.offset_element)) return false;
582 break;
583 }
584 }
585
586 // Then an End which is placed into the buffer the same as any other offset.
587 stack_.back().elements.emplace_back(
588 field_index, flatbuffers::Offset<flatbuffers::String>(
589 fbb_.EndVector(vector_elements_.size())));
590 return true;
591}
592
593bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
594 int64_t int_value) {
595 switch (elementary_type) {
596 case flatbuffers::ET_BOOL:
597 fbb_.PushElement<bool>(int_value);
598 return true;
599 case flatbuffers::ET_CHAR:
600 fbb_.PushElement<int8_t>(int_value);
601 return true;
602 case flatbuffers::ET_UCHAR:
603 fbb_.PushElement<uint8_t>(int_value);
604 return true;
605 case flatbuffers::ET_SHORT:
606 fbb_.PushElement<int16_t>(int_value);
607 return true;
608 case flatbuffers::ET_USHORT:
609 fbb_.PushElement<uint16_t>(int_value);
610 return true;
611 case flatbuffers::ET_INT:
612 fbb_.PushElement<int32_t>(int_value);
613 return true;
614 case flatbuffers::ET_UINT:
615 fbb_.PushElement<uint32_t>(int_value);
616 return true;
617 case flatbuffers::ET_LONG:
618 fbb_.PushElement<int64_t>(int_value);
619 return true;
620 case flatbuffers::ET_ULONG:
621 fbb_.PushElement<uint64_t>(int_value);
622 return true;
623 case flatbuffers::ET_FLOAT:
624 fbb_.PushElement<float>(int_value);
625 return true;
626 case flatbuffers::ET_DOUBLE:
627 fbb_.PushElement<double>(int_value);
628 return true;
629 case flatbuffers::ET_STRING:
630 case flatbuffers::ET_UTYPE:
631 case flatbuffers::ET_SEQUENCE:
632 printf("Mismatched type for field '%s'. Got: integer, expected %s\n",
633 stack_.back().field_name.c_str(),
634 ElementaryTypeName(elementary_type));
635 return false;
636 };
637 return false;
638}
639
640bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
641 double double_value) {
642 switch (elementary_type) {
643 case flatbuffers::ET_UTYPE:
644 case flatbuffers::ET_BOOL:
645 case flatbuffers::ET_CHAR:
646 case flatbuffers::ET_UCHAR:
647 case flatbuffers::ET_SHORT:
648 case flatbuffers::ET_USHORT:
649 case flatbuffers::ET_INT:
650 case flatbuffers::ET_UINT:
651 case flatbuffers::ET_LONG:
652 case flatbuffers::ET_ULONG:
653 case flatbuffers::ET_STRING:
654 case flatbuffers::ET_SEQUENCE:
655 printf("Mismatched type for field '%s'. Got: double, expected %s\n",
656 stack_.back().field_name.c_str(),
657 ElementaryTypeName(elementary_type));
658 return false;
659 case flatbuffers::ET_FLOAT:
660 fbb_.PushElement<float>(double_value);
661 return true;
662 case flatbuffers::ET_DOUBLE:
663 fbb_.PushElement<double>(double_value);
664 return true;
665 }
666 return false;
667}
668
669bool JsonParser::PushElement(
670 flatbuffers::ElementaryType elementary_type,
671 flatbuffers::Offset<flatbuffers::String> offset_value) {
672 switch (elementary_type) {
673 case flatbuffers::ET_UTYPE:
674 case flatbuffers::ET_BOOL:
675 case flatbuffers::ET_CHAR:
676 case flatbuffers::ET_UCHAR:
677 case flatbuffers::ET_SHORT:
678 case flatbuffers::ET_USHORT:
679 case flatbuffers::ET_INT:
680 case flatbuffers::ET_UINT:
681 case flatbuffers::ET_LONG:
682 case flatbuffers::ET_ULONG:
683 case flatbuffers::ET_FLOAT:
684 case flatbuffers::ET_DOUBLE:
685 printf("Mismatched type for field '%s'. Got: sequence, expected %s\n",
686 stack_.back().field_name.c_str(),
687 ElementaryTypeName(elementary_type));
688 return false;
689 case flatbuffers::ET_STRING:
690 case flatbuffers::ET_SEQUENCE:
691 fbb_.PushElement(offset_value);
692 return true;
693 }
694 return false;
695}
696
697} // namespace
698
699::std::vector<uint8_t> JsonToFlatbuffer(
700 const char *data, const flatbuffers::TypeTable *typetable) {
701 JsonParser p;
702 return p.Parse(data, typetable);
703}
704
705::std::string FlatbufferToJson(const uint8_t *buffer,
706 const ::flatbuffers::TypeTable *typetable,
707 bool multi_line) {
708 ::flatbuffers::ToStringVisitor tostring_visitor(
709 multi_line ? "\n" : " ", true, multi_line ? " " : "", multi_line);
710 IterateFlatBuffer(buffer, typetable, &tostring_visitor);
711 return tostring_visitor.s;
712}
713
714void Tokenizer::ConsumeWhitespace() {
715 while (true) {
716 if (*data_ == '\0') {
717 return;
718 }
719 // Skip any whitespace.
720 if (*data_ == ' ' || *data_ == '\r' || *data_ == '\t') {
721 ++data_;
722 } else if (*data_ == '\n') {
723 ++data_;
724 ++linenumber_;
725 } else {
726 // There is no fail. Once we are out of whitespace (including 0 of it),
727 // declare success.
728 return;
729 }
730 }
731}
732
733bool Tokenizer::Consume(const char *token) {
734 const char *original = data_;
735 while (true) {
736 // Finishing the token is success.
737 if (*token == '\0') {
738 return true;
739 }
740
741 // But finishing the data first is failure.
742 if (*data_ == '\0') {
743 data_ = original;
744 return false;
745 }
746
747 // Missmatch is failure.
748 if (*token != *data_) {
749 data_ = original;
750 return false;
751 }
752
753 ++data_;
754 ++token;
755 }
756}
757
758bool Tokenizer::ConsumeString(::std::string *s) {
759 // Under no conditions is it acceptible to run out of data while parsing a
760 // string. Any '\0' checks should confirm that.
761 const char *original = data_;
762 if (*data_ == '\0') {
763 return false;
764 }
765
766 // Expect the leading "
767 if (*data_ != '"') {
768 return false;
769 }
770
771 ++data_;
772 const char *last_parsed_data = data_;
773 *s = ::std::string();
774
775 while (true) {
776 if (*data_ == '\0') {
777 data_ = original;
778 return false;
779 }
780
781 // If we get an end or an escape, do something special.
782 if (*data_ == '"' || *data_ == '\\') {
783 // Save what we found up until now, not including this character.
784 *s += ::std::string(last_parsed_data, data_);
785
786 // Update the pointer.
787 last_parsed_data = data_;
788
789 // " is the end, declare victory.
790 if (*data_ == '"') {
791 ++data_;
792 return true;
793 } else {
794 ++data_;
795 // Now consume valid escape characters and add their representation onto
796 // the output string.
797 if (*data_ == '\0') {
798 data_ = original;
799 return false;
800 } else if (*data_ == '"') {
801 *s += "\"";
802 } else if (*data_ == '\\') {
803 *s += "\\";
804 } else if (*data_ == '/') {
805 *s += "/";
806 } else if (*data_ == 'b') {
807 *s += "\b";
808 } else if (*data_ == 'f') {
809 *s += "\f";
810 } else if (*data_ == 'n') {
811 *s += "\n";
812 } else if (*data_ == 'r') {
813 *s += "\r";
814 } else if (*data_ == 't') {
815 *s += "\t";
816 } else if (*data_ == 'u') {
817 // TODO(austin): Unicode should be valid, but I really don't care to
818 // do this now...
819 fprintf(stderr, "Unexpected unicode on line %d\n", linenumber_);
820 data_ = original;
821 return false;
822 }
823 }
824 // And skip the escaped character.
825 last_parsed_data = data_ + 1;
826 }
827
828 ++data_;
829 }
830}
831
832bool Tokenizer::ConsumeNumber(::std::string *s) {
833 // Under no conditions is it acceptible to run out of data while parsing a
834 // number. Any '\0' checks should confirm that.
835 *s = ::std::string();
836 const char *original = data_;
837
838 // Consume the leading - unconditionally.
839 Consume("-");
840
841 // Then, we either get a 0, or we get a nonzero. Only nonzero can be followed
842 // by a second number.
843 if (!Consume("0")) {
844 if (*data_ == '\0') {
845 return false;
846 } else if (*data_ >= '1' && *data_ <= '9') {
847 // This wasn't a zero, but was a valid digit. Consume it.
848 ++data_;
849 } else {
850 return false;
851 }
852
853 // Now consume any number of any digits.
854 while (true) {
855 if (*data_ == '\0') {
856 data_ = original;
857 return false;
858 }
859 if (*data_ < '0' || *data_ > '9') {
860 break;
861 }
862 ++data_;
863 }
864 }
865
866 // We could now have a decimal.
867 if (*data_ == '.') {
868 ++data_;
869 while (true) {
870 if (*data_ == '\0') {
871 data_ = original;
872 return false;
873 }
874 // And any number of digits.
875 if (*data_ < '0' || *data_ > '9') {
876 break;
877 }
878 ++data_;
879 }
880 }
881
882 // And now an exponent.
883 if (*data_ == 'e' || *data_ == 'E') {
884 ++data_;
885 if (*data_ == '\0') {
886 data_ = original;
887 return false;
888 }
889
890 // Which could have a +-
891 if (*data_ == '+' || *data_ == '-') {
892 ++data_;
893 }
894 int count = 0;
895 while (true) {
896 if (*data_ == '\0') {
897 data_ = original;
898 return false;
899 }
900 // And digits.
901 if (*data_ < '0' || *data_ > '9') {
902 break;
903 }
904 ++data_;
905 ++count;
906 }
907 // But, it is an error to have an exponent and nothing following it.
908 if (count == 0) {
909 data_ = original;
910 return false;
911 }
912 }
913
914 *s = ::std::string(original, data_);
915 return true;
916}
917
918Tokenizer::TokenType Tokenizer::Next() {
919 switch (state_) {
920 case State::kExpectObjectStart:
921 // We should always start out with a {
922 if (!Consume("{")) return TokenType::kError;
923
924 // Document that we just started an object.
925 object_type_.push_back(ObjectType::kObject);
926
927 ConsumeWhitespace();
928
Austin Schuh84314af2019-10-03 09:11:34 -0700929 if (Consume("}")) {
930 ConsumeWhitespace();
931 state_ = State::kExpectObjectEnd;
932 } else {
933 state_ = State::kExpectField;
934 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700935 return TokenType::kStartObject;
936
937 case State::kExpectField: {
938 // Fields are built up of strings, whitespace, and then a : (followed by
939 // whitespace...)
940 ::std::string s;
941 if (!ConsumeString(&s)) {
942 fprintf(stderr, "Error on line %d, expected string for field name.\n",
943 linenumber_);
944 return TokenType::kError;
945 }
946 field_name_ = ::std::move(s);
947
948 ConsumeWhitespace();
949
950 if (!Consume(":")) {
951 fprintf(stderr, "Error on line %d\n", linenumber_);
952 return TokenType::kError;
953 }
954
955 ConsumeWhitespace();
956
957 state_ = State::kExpectValue;
958
959 return TokenType::kField;
960 } break;
961 case State::kExpectValue: {
962 TokenType result = TokenType::kError;
963
964 ::std::string s;
965 if (Consume("{")) {
966 // Fields are in objects. Record and recurse.
967 object_type_.push_back(ObjectType::kObject);
968
969 ConsumeWhitespace();
970
971 state_ = State::kExpectField;
972 return TokenType::kStartObject;
973 } else if (Consume("[")) {
974 // Values are in arrays. Record and recurse.
975 object_type_.push_back(ObjectType::kArray);
976
977 ConsumeWhitespace();
978 state_ = State::kExpectValue;
979 return TokenType::kStartArray;
980 } else if (ConsumeString(&s)) {
981 // Parsed as a string, grab it.
982 field_value_ = ::std::move(s);
983 result = TokenType::kStringValue;
984 } else if (ConsumeNumber(&s)) {
985 // Parsed as a number, grab it.
986 field_value_ = ::std::move(s);
987 result = TokenType::kNumberValue;
988 } else if (Consume("true")) {
989 // Parsed as a true, grab it.
990 field_value_ = "true";
991 result = TokenType::kTrueValue;
992 } else if (Consume("false")) {
993 // Parsed as a false, grab it.
994 field_value_ = "false";
995 result = TokenType::kFalseValue;
996 } else {
997 // Couldn't parse, so we have a syntax error.
998 fprintf(stderr, "Error line %d, invalid field value.\n", linenumber_);
999 }
1000
1001 ConsumeWhitespace();
1002
1003 // After a field, we either have a , and another field (or value if we are
1004 // in an array), or we should be closing out the object (or array).
1005 if (Consume(",")) {
1006 ConsumeWhitespace();
1007 switch (object_type_.back()) {
1008 case ObjectType::kObject:
1009 state_ = State::kExpectField;
1010 break;
1011 case ObjectType::kArray:
1012 state_ = State::kExpectValue;
1013 break;
1014 }
1015 } else {
1016 // Sanity check that the stack is deep enough.
1017 if (object_type_.size() == 0) {
1018 fprintf(stderr, "Error on line %d\n", linenumber_);
1019 return TokenType::kError;
1020 }
1021
1022 // And then require closing out the object.
1023 switch (object_type_.back()) {
1024 case ObjectType::kObject:
1025 if (Consume("}")) {
1026 ConsumeWhitespace();
1027 state_ = State::kExpectObjectEnd;
1028 } else {
1029 return TokenType::kError;
1030 }
1031 break;
1032 case ObjectType::kArray:
1033 if (Consume("]")) {
1034 ConsumeWhitespace();
1035 state_ = State::kExpectArrayEnd;
1036 } else {
1037 return TokenType::kError;
1038 }
1039 break;
1040 }
1041 }
1042 return result;
1043 } break;
1044
1045 case State::kExpectArrayEnd:
1046 case State::kExpectObjectEnd: {
1047 const TokenType result = state_ == State::kExpectArrayEnd
1048 ? TokenType::kEndArray
1049 : TokenType::kEndObject;
1050 // This is a transient state so we can send 2 tokens out in a row. We
1051 // discover the object or array end at the end of reading the value.
1052 object_type_.pop_back();
1053 if (object_type_.size() == 0) {
1054 // We unwound the outer object. We should send kEnd next.
1055 state_ = State::kExpectEnd;
1056 } else if (object_type_.back() == ObjectType::kObject) {
1057 // If we are going into an object, it should either have another field
1058 // or end.
1059 if (Consume(",")) {
1060 ConsumeWhitespace();
1061 state_ = State::kExpectField;
1062 } else if (Consume("}")) {
1063 ConsumeWhitespace();
1064 state_ = State::kExpectObjectEnd;
1065 } else {
1066 return TokenType::kError;
1067 }
1068 } else if (object_type_.back() == ObjectType::kArray) {
1069 // If we are going into an array, it should either have another value
1070 // or end.
1071 if (Consume(",")) {
1072 ConsumeWhitespace();
1073 state_ = State::kExpectValue;
1074 } else if (Consume("]")) {
1075 ConsumeWhitespace();
1076 state_ = State::kExpectArrayEnd;
1077 } else {
1078 return TokenType::kError;
1079 }
1080 }
1081 // And then send out the correct token.
1082 return result;
1083 }
1084 case State::kExpectEnd:
1085 // If we are supposed to be done, confirm nothing is after the end.
1086 if (AtEnd()) {
1087 return TokenType::kEnd;
1088 } else {
1089 fprintf(stderr, "Data past end at line %d\n", linenumber_);
1090 return TokenType::kError;
1091 }
1092 }
1093 return TokenType::kError;
1094}
1095
1096bool Tokenizer::FieldAsInt(long long *value) {
1097 const char *pos = field_value().c_str();
1098 errno = 0;
1099 *value = strtoll(field_value().c_str(), const_cast<char **>(&pos), 10);
Austin Schuh84314af2019-10-03 09:11:34 -07001100 if (pos != field_value().c_str() + field_value().size() || errno != 0) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001101 return false;
1102 }
1103 return true;
1104}
1105
1106bool Tokenizer::FieldAsDouble(double *value) {
1107 const char *pos = field_value().c_str();
1108 errno = 0;
1109 *value = strtod(field_value().c_str(), const_cast<char **>(&pos));
1110
Austin Schuh84314af2019-10-03 09:11:34 -07001111 if (pos != field_value().c_str() + field_value().size() || errno != 0) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001112 return false;
1113 }
1114 return true;
1115}
1116
1117} // namespace aos