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