blob: 036ae0148964d6e7037ae62903506cce309100bb [file] [log] [blame]
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001#include "aos/json_to_flatbuffer.h"
2
3#include <cstddef>
James Kuszmaul3ae42262019-11-08 12:33:41 -08004#include <string_view>
5
Austin Schuh43c6a352019-09-30 22:22:10 -07006#include "aos/flatbuffer_utils.h"
Austin Schuhd7e252d2019-10-06 13:51:02 -07007#include "aos/json_tokenizer.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -07008#include "flatbuffers/flatbuffers.h"
9#include "flatbuffers/minireflect.h"
Austin Schuhe93d8642019-10-13 15:27:07 -070010#include "glog/logging.h"
Brian Silverman5c710412021-02-09 19:09:32 -080011#include "stdio.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -070012
13// TODO(austin): Can we just do an Offset<void> ? It doesn't matter, so maybe
14// just say that.
15//
16// TODO(austin): I've yet to see how to create an ET_UTYPE, so I don't know what
17// one is and how to test it. So everything rejects it.
18
19namespace aos {
20
21// Finds the field index in the table given the name.
22int FieldIndex(const flatbuffers::TypeTable *typetable,
23 const char *field_name) {
24 CHECK(typetable->values == nullptr);
25 for (size_t i = 0; i < typetable->num_elems; ++i) {
26 if (strcmp(field_name, typetable->names[i]) == 0) {
27 return i;
28 }
29 }
30 return -1;
31}
32
33namespace {
34
35// Class to hold one of the 3 json types for an array.
36struct Element {
37 // The type.
38 enum class ElementType { INT, DOUBLE, OFFSET };
39
40 // Constructs an Element holding an integer.
41 Element(int64_t new_int_element)
42 : int_element(new_int_element), type(ElementType::INT) {}
43 // Constructs an Element holding an double.
44 Element(double new_double_element)
45 : double_element(new_double_element), type(ElementType::DOUBLE) {}
46 // Constructs an Element holding an Offset.
47 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
48 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
49
50 // Union for the various datatypes.
51 union {
52 int64_t int_element;
53 double double_element;
54 flatbuffers::Offset<flatbuffers::String> offset_element;
55 };
56
57 // And an enum signaling which one is in use.
58 ElementType type;
59};
60
61// Structure to represent a field element.
62struct FieldElement {
63 FieldElement(int new_field_index, int64_t int_element)
64 : element(int_element), field_index(new_field_index) {}
65 FieldElement(int new_field_index, double double_element)
66 : element(double_element), field_index(new_field_index) {}
67 FieldElement(int new_field_index,
68 flatbuffers::Offset<flatbuffers::String> offset_element)
69 : element(offset_element), field_index(new_field_index) {}
70
71 // Data to write.
72 Element element;
73 // Field index. The type table which this index is for is stored outside this
74 // object.
75 int field_index;
76};
77
Austin Schuh43c6a352019-09-30 22:22:10 -070078// Adds a single element. This assumes that vectors have been dealt with
79// already. Returns true on success.
80bool AddSingleElement(const flatbuffers::TypeTable *typetable,
81 const FieldElement &field_element,
82 ::std::vector<bool> *fields_in_use,
83 flatbuffers::FlatBufferBuilder *fbb);
84bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
85 int64_t int_value, flatbuffers::FlatBufferBuilder *fbb);
86bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
87 double double_value, flatbuffers::FlatBufferBuilder *fbb);
88bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
89 flatbuffers::Offset<flatbuffers::String> offset_element,
90 flatbuffers::FlatBufferBuilder *fbb);
91
Austin Schuh43c6a352019-09-30 22:22:10 -070092// Writes an array of FieldElement (with the definition in the type
93// table) to the builder. Returns the offset of the table.
94flatbuffers::uoffset_t WriteTable(const flatbuffers::TypeTable *typetable,
95 const ::std::vector<FieldElement> &elements,
96 flatbuffers::FlatBufferBuilder *fbb) {
97 // End of a nested struct! Add it.
98 const flatbuffers::uoffset_t start = fbb->StartTable();
99
100 ::std::vector<bool> fields_in_use(typetable->num_elems, false);
101
102 for (const FieldElement &field_element : elements) {
103 AddSingleElement(typetable, field_element, &fields_in_use, fbb);
104 }
105
106 return fbb->EndTable(start);
107}
108
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700109// Class to parse JSON into a flatbuffer.
110//
111// The basic strategy is that we need to do everything backwards. So we need to
112// build up what we need to do fully in memory, then do it.
113//
114// The driver for this is that strings need to be fully created before the
115// tables that use them. Same for sub messages. But, we only know we have them
Austin Schuh43c6a352019-09-30 22:22:10 -0700116// all when the structure ends. So, store each sub message in a
117// FieldElement and put them in the table at the end when we finish up
118// each message. Same goes for vectors.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700119class JsonParser {
120 public:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800121 JsonParser(flatbuffers::FlatBufferBuilder *fbb) : fbb_(fbb) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700122 ~JsonParser() {}
123
124 // Parses the json into a flatbuffer. Returns either an empty vector on
125 // error, or a vector with the flatbuffer data in it.
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800126 flatbuffers::Offset<flatbuffers::Table> Parse(
127 const std::string_view data, const flatbuffers::TypeTable *typetable) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700128 flatbuffers::uoffset_t end = 0;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700129 bool result = DoParse(typetable, data, &end);
130
131 if (result) {
132 // On success, finish the table and build the vector.
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800133 return flatbuffers::Offset<flatbuffers::Table>(end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700134 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800135 return flatbuffers::Offset<flatbuffers::Table>(0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700136 }
137 }
138
139 private:
140 // Setters and getters for in_vector (at the current level of the stack)
141 bool in_vector() const { return stack_.back().in_vector; }
142 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
143
144 // Parses the flatbuffer. This is a second method so we can do easier
145 // cleanup at the top level. Returns true on success.
Austin Schuhd339a9b2019-10-05 21:33:32 -0700146 bool DoParse(const flatbuffers::TypeTable *typetable,
Austin Schuhd3936202020-04-07 20:11:07 -0700147 const std::string_view data, flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700148
149 // Adds *_value for the provided field. If we are in a vector, queues the
Alex Perrycb7da4b2019-08-28 19:35:56 -0700150 // data up in vector_elements. Returns true on success.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700151 bool AddElement(int field_index, int64_t int_value);
152 bool AddElement(int field_index, double double_value);
153 bool AddElement(int field_index, const ::std::string &data);
154
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700155 // Finishes a vector for the provided field index. Returns true on success.
156 bool FinishVector(int field_index);
157
158 // Pushes an element as part of a vector. Returns true on success.
159 bool PushElement(flatbuffers::ElementaryType elementary_type,
160 int64_t int_value);
161 bool PushElement(flatbuffers::ElementaryType elementary_type,
162 double double_value);
163 bool PushElement(flatbuffers::ElementaryType elementary_type,
164 flatbuffers::Offset<flatbuffers::String> offset_value);
165
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800166 flatbuffers::FlatBufferBuilder *fbb_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700167
168 // This holds the state information that is needed as you recurse into
169 // nested structures.
170 struct FlatBufferContext {
171 // Type of the current type.
172 const flatbuffers::TypeTable *typetable;
173 // If true, we are parsing a vector.
174 bool in_vector;
175 // The field index of the current field.
176 int field_index;
177 // Name of the current field.
178 ::std::string field_name;
179
180 // Field elements that need to be inserted.
181 ::std::vector<FieldElement> elements;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700182
183 // For scalar types (not strings, and not nested tables), the vector ends
184 // up being implemented as a start and end, and a block of data. So we
185 // can't just push offsets in as we go. We either need to reproduce the
186 // logic inside flatbuffers, or build up vectors of the data. Vectors will
187 // be a bit of extra stack space, but whatever.
188 //
189 // Strings and nested structures are vectors of offsets.
190 // into the vector. Once you get to the end, you build up a vector and
191 // push that into the field.
192 ::std::vector<Element> vector_elements;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700193 };
194 ::std::vector<FlatBufferContext> stack_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700195};
196
197bool JsonParser::DoParse(const flatbuffers::TypeTable *typetable,
James Kuszmaul3ae42262019-11-08 12:33:41 -0800198 const std::string_view data,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700199 flatbuffers::uoffset_t *table_end) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700200 ::std::vector<const flatbuffers::TypeTable *> stack;
201
202 Tokenizer t(data);
203
204 // Main loop. Run until we get an end.
205 while (true) {
206 Tokenizer::TokenType token = t.Next();
207
208 switch (token) {
209 case Tokenizer::TokenType::kEnd:
210 if (stack_.size() != 0) {
Austin Schuh217a9782019-12-21 23:02:50 -0800211 fprintf(stderr, "Failed to unwind stack all the way\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700212 return false;
213 } else {
214 return true;
215 }
216 break;
217 case Tokenizer::TokenType::kError:
218 return false;
219 break;
220
221 case Tokenizer::TokenType::kStartObject: // {
222 if (stack_.size() == 0) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700223 stack_.push_back({typetable, false, -1, "", {}, {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700224 } else {
225 int field_index = stack_.back().field_index;
226
227 const flatbuffers::TypeCode &type_code =
228 stack_.back().typetable->type_codes[field_index];
229
230 if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
Austin Schuh217a9782019-12-21 23:02:50 -0800231 fprintf(stderr, "Field '%s' is not a sequence\n",
232 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700233 return false;
234 }
235
236 flatbuffers::TypeFunction type_function =
237 stack_.back().typetable->type_refs[type_code.sequence_ref];
238
Alex Perrycb7da4b2019-08-28 19:35:56 -0700239 stack_.push_back({type_function(), false, -1, "", {}, {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700240 }
241 break;
242 case Tokenizer::TokenType::kEndObject: // }
243 if (stack_.size() == 0) {
244 // Somehow we popped more than we pushed. Error.
Austin Schuh217a9782019-12-21 23:02:50 -0800245 fprintf(stderr, "Empty stack\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700246 return false;
247 } else {
248 // End of a nested struct! Add it.
Austin Schuhd3936202020-04-07 20:11:07 -0700249 const flatbuffers::uoffset_t end =
250 WriteTable(stack_.back().typetable, stack_.back().elements, fbb_);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700251
252 // We now want to talk about the parent structure. Pop the child.
253 stack_.pop_back();
254
255 if (stack_.size() == 0) {
256 // Instead of queueing it up in the stack, return it through the
257 // passed in variable.
258 *table_end = end;
259 } else {
260 // And now we can add it.
261 const int field_index = stack_.back().field_index;
262
263 // Do the right thing if we are in a vector.
264 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700265 stack_.back().vector_elements.emplace_back(
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700266 flatbuffers::Offset<flatbuffers::String>(end));
267 } else {
268 stack_.back().elements.emplace_back(
269 field_index, flatbuffers::Offset<flatbuffers::String>(end));
270 }
271 }
272 }
273 break;
274
275 case Tokenizer::TokenType::kStartArray: // [
276 if (stack_.size() == 0) {
277 // We don't support an array of structs at the root level.
278 return false;
279 }
280 // Sanity check that we aren't trying to make a vector of vectors.
281 if (in_vector()) {
282 return false;
283 }
284 set_in_vector(true);
285
286 break;
287 case Tokenizer::TokenType::kEndArray: { // ]
288 if (!in_vector()) {
289 return false;
290 }
291
292 const int field_index = stack_.back().field_index;
293
294 if (!FinishVector(field_index)) return false;
295
296 set_in_vector(false);
297 } break;
298
299 case Tokenizer::TokenType::kTrueValue: // true
300 case Tokenizer::TokenType::kFalseValue: // false
301 case Tokenizer::TokenType::kNumberValue: {
302 bool is_int = true;
303 double double_value;
304 long long int_value;
305 if (token == Tokenizer::TokenType::kTrueValue) {
306 int_value = 1;
307 } else if (token == Tokenizer::TokenType::kFalseValue) {
308 int_value = 0;
309 } else if (!t.FieldAsInt(&int_value)) {
310 if (t.FieldAsDouble(&double_value)) {
311 is_int = false;
312 } else {
313 fprintf(stderr, "Got a invalid number '%s'\n",
314 t.field_value().c_str());
315 return false;
316 }
317 }
318
319 const int field_index = stack_.back().field_index;
320
321 if (is_int) {
322 // No need to get too stressed about bool vs int. Convert them all.
323 int64_t val = int_value;
324 if (!AddElement(field_index, val)) return false;
325 } else {
326 if (!AddElement(field_index, double_value)) return false;
327 }
328 } break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700329 case Tokenizer::TokenType::kStringValue: // string value
330 {
331 const int field_index = stack_.back().field_index;
332
333 if (!AddElement(field_index, t.field_value())) return false;
334 } break;
335 case Tokenizer::TokenType::kField: // field name
336 {
337 stack_.back().field_name = t.field_name();
338 stack_.back().field_index = FieldIndex(
339 stack_.back().typetable, stack_.back().field_name.c_str());
340
341 if (stack_.back().field_index == -1) {
Austin Schuh217a9782019-12-21 23:02:50 -0800342 fprintf(stderr, "Invalid field name '%s'\n",
343 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700344 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
Austin Schuh7c75e582020-11-14 16:41:18 -0800356 if (type_code.is_repeating != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800357 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700358 return false;
359 }
360
361 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700362 stack_.back().vector_elements.emplace_back(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700363 } 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
Austin Schuh7c75e582020-11-14 16:41:18 -0800373 if (type_code.is_repeating != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800374 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700375 return false;
376 }
377
378 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700379 stack_.back().vector_elements.emplace_back(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700380 } 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
Austin Schuh7c75e582020-11-14 16:41:18 -0800390 if (type_code.is_repeating != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800391 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700392 return false;
393 }
394
Alex Perrycb7da4b2019-08-28 19:35:56 -0700395 const flatbuffers::ElementaryType elementary_type =
396 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
397 switch (elementary_type) {
398 case flatbuffers::ET_CHAR:
399 case flatbuffers::ET_UCHAR:
400 case flatbuffers::ET_SHORT:
401 case flatbuffers::ET_USHORT:
402 case flatbuffers::ET_INT:
403 case flatbuffers::ET_UINT:
404 case flatbuffers::ET_LONG:
405 case flatbuffers::ET_ULONG:
406 if (type_code.sequence_ref != -1) {
407 // We have an enum.
408 const flatbuffers::TypeTable *type_table = stack_.back().typetable;
409 flatbuffers::TypeFunction type_function =
410 type_table->type_refs[type_code.sequence_ref];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700411
Alex Perrycb7da4b2019-08-28 19:35:56 -0700412 const flatbuffers::TypeTable *enum_type_table = type_function();
413
414 CHECK_EQ(enum_type_table->st, flatbuffers::ST_ENUM);
415
416 int64_t int_value = 0;
417 bool found = false;
418 for (size_t i = 0; i < enum_type_table->num_elems; ++i) {
419 if (data == enum_type_table->names[i]) {
Brian Silverman5c710412021-02-09 19:09:32 -0800420 if (enum_type_table->values) {
421 int_value = enum_type_table->values[i];
422 } else {
423 int_value = i;
424 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700425 found = true;
426 break;
427 }
428 }
429
430 if (!found) {
Austin Schuh217a9782019-12-21 23:02:50 -0800431 fprintf(stderr, "Enum value '%s' not found for field '%s'\n",
432 data.c_str(), type_table->names[field_index]);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700433 return false;
434 }
435
436 if (in_vector()) {
437 stack_.back().vector_elements.emplace_back(int_value);
438 } else {
439 stack_.back().elements.emplace_back(field_index, int_value);
440 }
441 return true;
442 }
443 case flatbuffers::ET_UTYPE:
444 case flatbuffers::ET_BOOL:
445 case flatbuffers::ET_FLOAT:
446 case flatbuffers::ET_DOUBLE:
447 case flatbuffers::ET_STRING:
448 case flatbuffers::ET_SEQUENCE:
449 break;
450 }
451
452 if (in_vector()) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800453 stack_.back().vector_elements.emplace_back(fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700454 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800455 stack_.back().elements.emplace_back(field_index, fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700456 }
457 return true;
458}
459
Austin Schuh43c6a352019-09-30 22:22:10 -0700460bool AddSingleElement(const flatbuffers::TypeTable *typetable,
461 const FieldElement &field_element,
462 ::std::vector<bool> *fields_in_use,
463 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700464 if ((*fields_in_use)[field_element.field_index]) {
Austin Schuh217a9782019-12-21 23:02:50 -0800465 fprintf(stderr, "Duplicate field: '%s'\n",
466 typetable->names[field_element.field_index]);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700467 return false;
468 }
469
470 (*fields_in_use)[field_element.field_index] = true;
471
472 switch (field_element.element.type) {
473 case Element::ElementType::INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700474 return AddSingleElement(typetable, field_element.field_index,
475 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700476 case Element::ElementType::DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700477 return AddSingleElement(typetable, field_element.field_index,
478 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700479 case Element::ElementType::OFFSET:
Austin Schuh43c6a352019-09-30 22:22:10 -0700480 return AddSingleElement(typetable, field_element.field_index,
481 field_element.element.offset_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700482 }
483 return false;
484}
485
Austin Schuh43c6a352019-09-30 22:22:10 -0700486bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
487 int64_t int_value, flatbuffers::FlatBufferBuilder *fbb
488
489) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700490 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
491 static_cast<flatbuffers::voffset_t>(field_index));
492
Austin Schuh43c6a352019-09-30 22:22:10 -0700493 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700494
495 const flatbuffers::ElementaryType elementary_type =
496 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
497 switch (elementary_type) {
498 case flatbuffers::ET_BOOL:
Austin Schuh43c6a352019-09-30 22:22:10 -0700499 fbb->AddElement<bool>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700500 return true;
501 case flatbuffers::ET_CHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700502 fbb->AddElement<int8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700503 return true;
504 case flatbuffers::ET_UCHAR:
Austin Schuh43c6a352019-09-30 22:22:10 -0700505 fbb->AddElement<uint8_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700506 return true;
507 case flatbuffers::ET_SHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700508 fbb->AddElement<int16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700509 return true;
510 case flatbuffers::ET_USHORT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700511 fbb->AddElement<uint16_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700512 return true;
513 case flatbuffers::ET_INT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700514 fbb->AddElement<int32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700515 return true;
516 case flatbuffers::ET_UINT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700517 fbb->AddElement<uint32_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700518 return true;
519 case flatbuffers::ET_LONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700520 fbb->AddElement<int64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700521 return true;
522 case flatbuffers::ET_ULONG:
Austin Schuh43c6a352019-09-30 22:22:10 -0700523 fbb->AddElement<uint64_t>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700524 return true;
525 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700526 fbb->AddElement<float>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700527 return true;
528 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700529 fbb->AddElement<double>(field_offset, int_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700530 return true;
531 case flatbuffers::ET_STRING:
532 case flatbuffers::ET_UTYPE:
533 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800534 fprintf(
535 stderr, "Mismatched type for field '%s'. Got: integer, expected %s\n",
536 typetable->names[field_index], ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700537 return false;
538 };
539 return false;
540}
541
Austin Schuh43c6a352019-09-30 22:22:10 -0700542bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
543 double double_value,
544 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700545 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
546 static_cast<flatbuffers::voffset_t>(field_index));
547
Austin Schuh43c6a352019-09-30 22:22:10 -0700548 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700549
550 const flatbuffers::ElementaryType elementary_type =
551 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
552 switch (elementary_type) {
553 case flatbuffers::ET_UTYPE:
554 case flatbuffers::ET_BOOL:
555 case flatbuffers::ET_CHAR:
556 case flatbuffers::ET_UCHAR:
557 case flatbuffers::ET_SHORT:
558 case flatbuffers::ET_USHORT:
559 case flatbuffers::ET_INT:
560 case flatbuffers::ET_UINT:
561 case flatbuffers::ET_LONG:
562 case flatbuffers::ET_ULONG:
563 case flatbuffers::ET_STRING:
564 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800565 fprintf(
566 stderr, "Mismatched type for field '%s'. Got: double, expected %s\n",
567 typetable->names[field_index], ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700568 return false;
569 case flatbuffers::ET_FLOAT:
Austin Schuh43c6a352019-09-30 22:22:10 -0700570 fbb->AddElement<float>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700571 return true;
572 case flatbuffers::ET_DOUBLE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700573 fbb->AddElement<double>(field_offset, double_value, 0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700574 return true;
575 }
576 return false;
577}
Austin Schuh43c6a352019-09-30 22:22:10 -0700578bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
579 flatbuffers::Offset<flatbuffers::String> offset_element,
580 flatbuffers::FlatBufferBuilder *fbb) {
581 flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700582
583 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
584 static_cast<flatbuffers::voffset_t>(field_index));
585
586 // Vectors will always be Offset<>'s.
Austin Schuh7c75e582020-11-14 16:41:18 -0800587 if (type_code.is_repeating) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700588 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700589 return true;
590 }
591
592 const flatbuffers::ElementaryType elementary_type =
593 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
594 switch (elementary_type) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700595 case flatbuffers::ET_CHAR:
596 case flatbuffers::ET_UCHAR:
597 case flatbuffers::ET_SHORT:
598 case flatbuffers::ET_USHORT:
599 case flatbuffers::ET_INT:
600 case flatbuffers::ET_UINT:
601 case flatbuffers::ET_LONG:
602 case flatbuffers::ET_ULONG:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700603 case flatbuffers::ET_UTYPE:
604 case flatbuffers::ET_BOOL:
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700605 case flatbuffers::ET_FLOAT:
606 case flatbuffers::ET_DOUBLE:
Austin Schuh217a9782019-12-21 23:02:50 -0800607 fprintf(
608 stderr, "Mismatched type for field '%s'. Got: string, expected %s\n",
609 typetable->names[field_index], ElementaryTypeName(elementary_type));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700610 CHECK_EQ(type_code.sequence_ref, -1)
611 << ": Field name " << typetable->names[field_index]
612 << " Got string expected " << ElementaryTypeName(elementary_type);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700613 return false;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700614 case flatbuffers::ET_STRING:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700615 CHECK_EQ(type_code.sequence_ref, -1);
616 case flatbuffers::ET_SEQUENCE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700617 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700618 return true;
619 }
620 return false;
621}
622
623bool JsonParser::FinishVector(int field_index) {
624 flatbuffers::TypeCode type_code =
625 stack_.back().typetable->type_codes[field_index];
626
627 const flatbuffers::ElementaryType elementary_type =
628 static_cast<flatbuffers::ElementaryType>(type_code.base_type);
629
630 // Vectors have a start (unfortunately which needs to know the size)
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800631 fbb_->StartVector(
Alex Perrycb7da4b2019-08-28 19:35:56 -0700632 stack_.back().vector_elements.size(),
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700633 flatbuffers::InlineSize(elementary_type, stack_.back().typetable));
634
635 // Then the data (in reverse order for some reason...)
Alex Perrycb7da4b2019-08-28 19:35:56 -0700636 for (size_t i = stack_.back().vector_elements.size(); i > 0;) {
637 const Element &element = stack_.back().vector_elements[--i];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700638 switch (element.type) {
639 case Element::ElementType::INT:
640 if (!PushElement(elementary_type, element.int_element)) return false;
641 break;
642 case Element::ElementType::DOUBLE:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700643 CHECK_EQ(type_code.sequence_ref, -1)
644 << ": Field index is " << field_index;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700645 if (!PushElement(elementary_type, element.double_element)) return false;
646 break;
647 case Element::ElementType::OFFSET:
648 if (!PushElement(elementary_type, element.offset_element)) return false;
649 break;
650 }
651 }
652
653 // Then an End which is placed into the buffer the same as any other offset.
654 stack_.back().elements.emplace_back(
655 field_index, flatbuffers::Offset<flatbuffers::String>(
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800656 fbb_->EndVector(stack_.back().vector_elements.size())));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700657 stack_.back().vector_elements.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700658 return true;
659}
660
661bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
662 int64_t int_value) {
663 switch (elementary_type) {
664 case flatbuffers::ET_BOOL:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800665 fbb_->PushElement<bool>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700666 return true;
667 case flatbuffers::ET_CHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800668 fbb_->PushElement<int8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700669 return true;
670 case flatbuffers::ET_UCHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800671 fbb_->PushElement<uint8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700672 return true;
673 case flatbuffers::ET_SHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800674 fbb_->PushElement<int16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700675 return true;
676 case flatbuffers::ET_USHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800677 fbb_->PushElement<uint16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700678 return true;
679 case flatbuffers::ET_INT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800680 fbb_->PushElement<int32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700681 return true;
682 case flatbuffers::ET_UINT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800683 fbb_->PushElement<uint32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700684 return true;
685 case flatbuffers::ET_LONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800686 fbb_->PushElement<int64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700687 return true;
688 case flatbuffers::ET_ULONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800689 fbb_->PushElement<uint64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700690 return true;
691 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800692 fbb_->PushElement<float>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700693 return true;
694 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800695 fbb_->PushElement<double>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700696 return true;
697 case flatbuffers::ET_STRING:
698 case flatbuffers::ET_UTYPE:
699 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800700 fprintf(stderr,
701 "Mismatched type for field '%s'. Got: integer, expected %s\n",
702 stack_.back().field_name.c_str(),
703 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700704 return false;
705 };
706 return false;
707}
708
709bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
710 double double_value) {
711 switch (elementary_type) {
712 case flatbuffers::ET_UTYPE:
713 case flatbuffers::ET_BOOL:
714 case flatbuffers::ET_CHAR:
715 case flatbuffers::ET_UCHAR:
716 case flatbuffers::ET_SHORT:
717 case flatbuffers::ET_USHORT:
718 case flatbuffers::ET_INT:
719 case flatbuffers::ET_UINT:
720 case flatbuffers::ET_LONG:
721 case flatbuffers::ET_ULONG:
722 case flatbuffers::ET_STRING:
723 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800724 fprintf(stderr,
725 "Mismatched type for field '%s'. Got: double, expected %s\n",
726 stack_.back().field_name.c_str(),
727 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700728 return false;
729 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800730 fbb_->PushElement<float>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700731 return true;
732 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800733 fbb_->PushElement<double>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700734 return true;
735 }
736 return false;
737}
738
739bool JsonParser::PushElement(
740 flatbuffers::ElementaryType elementary_type,
741 flatbuffers::Offset<flatbuffers::String> offset_value) {
742 switch (elementary_type) {
743 case flatbuffers::ET_UTYPE:
744 case flatbuffers::ET_BOOL:
745 case flatbuffers::ET_CHAR:
746 case flatbuffers::ET_UCHAR:
747 case flatbuffers::ET_SHORT:
748 case flatbuffers::ET_USHORT:
749 case flatbuffers::ET_INT:
750 case flatbuffers::ET_UINT:
751 case flatbuffers::ET_LONG:
752 case flatbuffers::ET_ULONG:
753 case flatbuffers::ET_FLOAT:
754 case flatbuffers::ET_DOUBLE:
Austin Schuh217a9782019-12-21 23:02:50 -0800755 fprintf(stderr,
756 "Mismatched type for field '%s'. Got: sequence, expected %s\n",
757 stack_.back().field_name.c_str(),
758 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700759 return false;
760 case flatbuffers::ET_STRING:
761 case flatbuffers::ET_SEQUENCE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800762 fbb_->PushElement(offset_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700763 return true;
764 }
765 return false;
766}
767
768} // namespace
769
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800770flatbuffers::Offset<flatbuffers::Table> JsonToFlatbuffer(
771 const std::string_view data, const flatbuffers::TypeTable *typetable,
772 flatbuffers::FlatBufferBuilder *fbb) {
773 JsonParser p(fbb);
774 return p.Parse(data, typetable);
775}
776
Austin Schuhe93d8642019-10-13 15:27:07 -0700777flatbuffers::DetachedBuffer JsonToFlatbuffer(
Austin Schuhd3936202020-04-07 20:11:07 -0700778 const std::string_view data, const flatbuffers::TypeTable *typetable) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800779 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -0800780 fbb.ForceDefaults(true);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800781
782 const flatbuffers::Offset<flatbuffers::Table> result =
783 JsonToFlatbuffer(data, typetable, &fbb);
784 if (result.o != 0) {
785 fbb.Finish(result);
786
787 return fbb.Release();
788 } else {
789 // Otherwise return an empty vector.
790 return flatbuffers::DetachedBuffer();
791 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700792}
793
Austin Schuhd3936202020-04-07 20:11:07 -0700794namespace {
795
796// A visitor which manages skipping the contents of vectors that are longer than
797// a specified threshold.
798class TruncatingStringVisitor : public flatbuffers::IterationVisitor {
799 public:
800 TruncatingStringVisitor(size_t max_vector_size, std::string delimiter,
801 bool quotes, std::string indent, bool vdelimited)
802 : max_vector_size_(max_vector_size),
803 to_string_(delimiter, quotes, indent, vdelimited) {}
804 ~TruncatingStringVisitor() override {}
805
806 void StartSequence() override {
807 if (should_skip()) return;
808 to_string_.StartSequence();
809 }
810 void EndSequence() override {
811 if (should_skip()) return;
812 to_string_.EndSequence();
813 }
814 void Field(size_t field_idx, size_t set_idx, flatbuffers::ElementaryType type,
Austin Schuh7c75e582020-11-14 16:41:18 -0800815 bool is_repeating, const flatbuffers::TypeTable *type_table,
Austin Schuhd3936202020-04-07 20:11:07 -0700816 const char *name, const uint8_t *val) override {
817 if (should_skip()) return;
Austin Schuh7c75e582020-11-14 16:41:18 -0800818 to_string_.Field(field_idx, set_idx, type, is_repeating, type_table, name,
Austin Schuhd3936202020-04-07 20:11:07 -0700819 val);
820 }
821 void UType(uint8_t value, const char *name) override {
822 if (should_skip()) return;
823 to_string_.UType(value, name);
824 }
825 void Bool(bool value) override {
826 if (should_skip()) return;
827 to_string_.Bool(value);
828 }
829 void Char(int8_t value, const char *name) override {
830 if (should_skip()) return;
831 to_string_.Char(value, name);
832 }
833 void UChar(uint8_t value, const char *name) override {
834 if (should_skip()) return;
835 to_string_.UChar(value, name);
836 }
837 void Short(int16_t value, const char *name) override {
838 if (should_skip()) return;
839 to_string_.Short(value, name);
840 }
841 void UShort(uint16_t value, const char *name) override {
842 if (should_skip()) return;
843 to_string_.UShort(value, name);
844 }
845 void Int(int32_t value, const char *name) override {
846 if (should_skip()) return;
847 to_string_.Int(value, name);
848 }
849 void UInt(uint32_t value, const char *name) override {
850 if (should_skip()) return;
851 to_string_.UInt(value, name);
852 }
853 void Long(int64_t value) override {
854 if (should_skip()) return;
855 to_string_.Long(value);
856 }
857 void ULong(uint64_t value) override {
858 if (should_skip()) return;
859 to_string_.ULong(value);
860 }
861 void Float(float value) override {
862 if (should_skip()) return;
863 to_string_.Float(value);
864 }
865 void Double(double value) override {
866 if (should_skip()) return;
867 to_string_.Double(value);
868 }
869 void String(const flatbuffers::String *value) override {
870 if (should_skip()) return;
871 to_string_.String(value);
872 }
873 void Unknown(const uint8_t *value) override {
874 if (should_skip()) return;
875 to_string_.Unknown(value);
876 }
877 void Element(size_t i, flatbuffers::ElementaryType type,
878 const flatbuffers::TypeTable *type_table,
879 const uint8_t *val) override {
880 if (should_skip()) return;
881 to_string_.Element(i, type, type_table, val);
882 }
883
884 virtual void StartVector(size_t size) override {
885 if (should_skip()) {
886 ++skip_levels_;
887 return;
888 }
889 if (size > max_vector_size_) {
890 ++skip_levels_;
891 to_string_.s += "[ ... " + std::to_string(size) + " elements ... ]";
892 return;
893 }
894 to_string_.StartVector(size);
895 }
896 virtual void EndVector() override {
897 if (should_skip()) {
898 --skip_levels_;
899 return;
900 }
901 to_string_.EndVector();
902 }
903
904 std::string &string() { return to_string_.s; }
905
906 private:
907 bool should_skip() const { return skip_levels_ > 0; }
908
909 const size_t max_vector_size_;
910 flatbuffers::ToStringVisitor to_string_;
911 int skip_levels_ = 0;
912};
913
914} // namespace
915
Austin Schuhe93d8642019-10-13 15:27:07 -0700916::std::string TableFlatbufferToJson(const flatbuffers::Table *t,
917 const ::flatbuffers::TypeTable *typetable,
Ravago Jonescf453ab2020-05-06 21:14:53 -0700918 JsonOptions json_options) {
Austin Schuhe93d8642019-10-13 15:27:07 -0700919 // It is pretty common to get passed in a nullptr when a test fails. Rather
920 // than CHECK, return a more user friendly result.
921 if (t == nullptr) {
922 return "null";
923 }
Ravago Jonescf453ab2020-05-06 21:14:53 -0700924 TruncatingStringVisitor tostring_visitor(
925 json_options.max_vector_size, json_options.multi_line ? "\n" : " ", true,
926 json_options.multi_line ? " " : "", json_options.multi_line);
Austin Schuhe93d8642019-10-13 15:27:07 -0700927 flatbuffers::IterateObject(reinterpret_cast<const uint8_t *>(t), typetable,
928 &tostring_visitor);
Austin Schuhd3936202020-04-07 20:11:07 -0700929 return tostring_visitor.string();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700930}
931
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700932} // namespace aos