blob: 023deea4212a726879eeb8fb7cbcd06b70c0744d [file] [log] [blame]
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001#include "aos/json_to_flatbuffer.h"
2
3#include <cstddef>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cstdio>
James Kuszmaul3ae42262019-11-08 12:33:41 -08005#include <string_view>
6
Austin Schuh3e95e5d2019-09-20 00:08:54 -07007#include "flatbuffers/flatbuffers.h"
8#include "flatbuffers/minireflect.h"
Austin Schuhe93d8642019-10-13 15:27:07 -07009#include "glog/logging.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -070010
Philipp Schrader790cb542023-07-05 21:06:52 -070011#include "aos/flatbuffer_utils.h"
12#include "aos/json_tokenizer.h"
13
Austin Schuh3e95e5d2019-09-20 00:08:54 -070014// TODO(austin): Can we just do an Offset<void> ? It doesn't matter, so maybe
15// just say that.
16//
17// TODO(austin): I've yet to see how to create an ET_UTYPE, so I don't know what
18// one is and how to test it. So everything rejects it.
19
20namespace aos {
Austin Schuh3e95e5d2019-09-20 00:08:54 -070021namespace {
22
23// Class to hold one of the 3 json types for an array.
24struct Element {
25 // The type.
26 enum class ElementType { INT, DOUBLE, OFFSET };
27
28 // Constructs an Element holding an integer.
29 Element(int64_t new_int_element)
30 : int_element(new_int_element), type(ElementType::INT) {}
31 // Constructs an Element holding an double.
32 Element(double new_double_element)
33 : double_element(new_double_element), type(ElementType::DOUBLE) {}
34 // Constructs an Element holding an Offset.
35 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
36 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
37
38 // Union for the various datatypes.
39 union {
40 int64_t int_element;
41 double double_element;
42 flatbuffers::Offset<flatbuffers::String> offset_element;
43 };
44
45 // And an enum signaling which one is in use.
46 ElementType type;
47};
48
49// Structure to represent a field element.
50struct FieldElement {
51 FieldElement(int new_field_index, int64_t int_element)
52 : element(int_element), field_index(new_field_index) {}
53 FieldElement(int new_field_index, double double_element)
54 : element(double_element), field_index(new_field_index) {}
55 FieldElement(int new_field_index,
56 flatbuffers::Offset<flatbuffers::String> offset_element)
57 : element(offset_element), field_index(new_field_index) {}
58
59 // Data to write.
60 Element element;
61 // Field index. The type table which this index is for is stored outside this
62 // object.
63 int field_index;
64};
65
Austin Schuh43c6a352019-09-30 22:22:10 -070066// Adds a single element. This assumes that vectors have been dealt with
67// already. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -080068bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -070069 ::std::vector<bool> *fields_in_use,
70 flatbuffers::FlatBufferBuilder *fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -080071bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
72 flatbuffers::FlatBufferBuilder *fbb);
73bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
74 flatbuffers::FlatBufferBuilder *fbb);
75bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -070076 flatbuffers::Offset<flatbuffers::String> offset_element,
77 flatbuffers::FlatBufferBuilder *fbb);
78
Brian Silvermancf4fb662021-02-10 17:54:53 -080079// Writes an array of FieldElement (with the definition in "type") to the
80// builder. Returns the offset of the resulting table.
81flatbuffers::uoffset_t WriteTable(FlatbufferType type,
Austin Schuh43c6a352019-09-30 22:22:10 -070082 const ::std::vector<FieldElement> &elements,
83 flatbuffers::FlatBufferBuilder *fbb) {
84 // End of a nested struct! Add it.
85 const flatbuffers::uoffset_t start = fbb->StartTable();
86
Brian Silvermancf4fb662021-02-10 17:54:53 -080087 ::std::vector<bool> fields_in_use(type.NumberFields(), false);
Austin Schuh43c6a352019-09-30 22:22:10 -070088
89 for (const FieldElement &field_element : elements) {
Brian Silvermancf4fb662021-02-10 17:54:53 -080090 AddSingleElement(type, field_element, &fields_in_use, fbb);
Austin Schuh43c6a352019-09-30 22:22:10 -070091 }
92
93 return fbb->EndTable(start);
94}
95
Austin Schuh3e95e5d2019-09-20 00:08:54 -070096// Class to parse JSON into a flatbuffer.
97//
98// The basic strategy is that we need to do everything backwards. So we need to
99// build up what we need to do fully in memory, then do it.
100//
101// The driver for this is that strings need to be fully created before the
102// tables that use them. Same for sub messages. But, we only know we have them
Austin Schuh43c6a352019-09-30 22:22:10 -0700103// all when the structure ends. So, store each sub message in a
104// FieldElement and put them in the table at the end when we finish up
105// each message. Same goes for vectors.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700106class JsonParser {
107 public:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800108 JsonParser(flatbuffers::FlatBufferBuilder *fbb) : fbb_(fbb) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700109 ~JsonParser() {}
110
111 // Parses the json into a flatbuffer. Returns either an empty vector on
112 // error, or a vector with the flatbuffer data in it.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800113 flatbuffers::Offset<flatbuffers::Table> Parse(const std::string_view data,
114 FlatbufferType type) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700115 flatbuffers::uoffset_t end = 0;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800116 bool result = DoParse(type, data, &end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700117
118 if (result) {
119 // On success, finish the table and build the vector.
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800120 return flatbuffers::Offset<flatbuffers::Table>(end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700121 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800122 return flatbuffers::Offset<flatbuffers::Table>(0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700123 }
124 }
125
126 private:
127 // Setters and getters for in_vector (at the current level of the stack)
128 bool in_vector() const { return stack_.back().in_vector; }
129 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
130
131 // Parses the flatbuffer. This is a second method so we can do easier
132 // cleanup at the top level. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800133 bool DoParse(FlatbufferType type, const std::string_view data,
134 flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700135
136 // Adds *_value for the provided field. If we are in a vector, queues the
Alex Perrycb7da4b2019-08-28 19:35:56 -0700137 // data up in vector_elements. Returns true on success.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700138 bool AddElement(int field_index, int64_t int_value);
139 bool AddElement(int field_index, double double_value);
140 bool AddElement(int field_index, const ::std::string &data);
141
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700142 // Finishes a vector for the provided field index. Returns true on success.
143 bool FinishVector(int field_index);
144
145 // Pushes an element as part of a vector. Returns true on success.
146 bool PushElement(flatbuffers::ElementaryType elementary_type,
147 int64_t int_value);
148 bool PushElement(flatbuffers::ElementaryType elementary_type,
149 double double_value);
150 bool PushElement(flatbuffers::ElementaryType elementary_type,
151 flatbuffers::Offset<flatbuffers::String> offset_value);
152
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800153 flatbuffers::FlatBufferBuilder *fbb_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700154
155 // This holds the state information that is needed as you recurse into
156 // nested structures.
157 struct FlatBufferContext {
158 // Type of the current type.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800159 FlatbufferType type;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700160 // If true, we are parsing a vector.
161 bool in_vector;
162 // The field index of the current field.
163 int field_index;
164 // Name of the current field.
165 ::std::string field_name;
166
167 // Field elements that need to be inserted.
168 ::std::vector<FieldElement> elements;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700169
170 // For scalar types (not strings, and not nested tables), the vector ends
171 // up being implemented as a start and end, and a block of data. So we
172 // can't just push offsets in as we go. We either need to reproduce the
173 // logic inside flatbuffers, or build up vectors of the data. Vectors will
174 // be a bit of extra stack space, but whatever.
175 //
176 // Strings and nested structures are vectors of offsets.
177 // into the vector. Once you get to the end, you build up a vector and
178 // push that into the field.
179 ::std::vector<Element> vector_elements;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700180 };
181 ::std::vector<FlatBufferContext> stack_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700182};
183
Brian Silvermancf4fb662021-02-10 17:54:53 -0800184bool JsonParser::DoParse(FlatbufferType type, const std::string_view data,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700185 flatbuffers::uoffset_t *table_end) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800186 ::std::vector<FlatbufferType> stack;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700187
188 Tokenizer t(data);
189
190 // Main loop. Run until we get an end.
191 while (true) {
192 Tokenizer::TokenType token = t.Next();
193
194 switch (token) {
195 case Tokenizer::TokenType::kEnd:
196 if (stack_.size() != 0) {
Austin Schuh217a9782019-12-21 23:02:50 -0800197 fprintf(stderr, "Failed to unwind stack all the way\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700198 return false;
199 } else {
200 return true;
201 }
202 break;
203 case Tokenizer::TokenType::kError:
204 return false;
205 break;
206
207 case Tokenizer::TokenType::kStartObject: // {
208 if (stack_.size() == 0) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800209 stack_.push_back({type, false, -1, "", {}, {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700210 } else {
211 int field_index = stack_.back().field_index;
212
Brian Silvermancf4fb662021-02-10 17:54:53 -0800213 if (!stack_.back().type.FieldIsSequence(field_index)) {
Austin Schuh217a9782019-12-21 23:02:50 -0800214 fprintf(stderr, "Field '%s' is not a sequence\n",
215 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700216 return false;
217 }
218
James Kuszmaulbb60dfd2023-01-05 17:13:11 -0800219 if (in_vector() != stack_.back().type.FieldIsRepeating(field_index)) {
220 fprintf(stderr,
221 "Field '%s' is%s supposed to be a vector, but is a %s.\n",
222 stack_.back().field_name.c_str(), in_vector() ? " not" : "",
223 in_vector() ? "vector" : "bare object");
224 return false;
225 }
226
Brian Silvermancf4fb662021-02-10 17:54:53 -0800227 stack_.push_back({stack_.back().type.FieldType(field_index),
228 false,
229 -1,
230 "",
231 {},
232 {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700233 }
234 break;
235 case Tokenizer::TokenType::kEndObject: // }
236 if (stack_.size() == 0) {
237 // Somehow we popped more than we pushed. Error.
Austin Schuh217a9782019-12-21 23:02:50 -0800238 fprintf(stderr, "Empty stack\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700239 return false;
240 } else {
241 // End of a nested struct! Add it.
Austin Schuhd3936202020-04-07 20:11:07 -0700242 const flatbuffers::uoffset_t end =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800243 WriteTable(stack_.back().type, stack_.back().elements, fbb_);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700244
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()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700258 stack_.back().vector_elements.emplace_back(
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700259 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;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700322 case Tokenizer::TokenType::kStringValue: // string value
323 {
324 const int field_index = stack_.back().field_index;
325
326 if (!AddElement(field_index, t.field_value())) return false;
327 } break;
328 case Tokenizer::TokenType::kField: // field name
329 {
330 stack_.back().field_name = t.field_name();
Brian Silvermancf4fb662021-02-10 17:54:53 -0800331 stack_.back().field_index =
332 stack_.back().type.FieldIndex(stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700333
334 if (stack_.back().field_index == -1) {
Austin Schuh217a9782019-12-21 23:02:50 -0800335 fprintf(stderr, "Invalid field name '%s'\n",
336 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700337 return false;
338 }
339 } break;
340 }
341 }
342 return false;
343}
344
345bool JsonParser::AddElement(int field_index, int64_t int_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800346 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800347 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700348 return false;
349 }
350
351 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700352 stack_.back().vector_elements.emplace_back(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700353 } else {
354 stack_.back().elements.emplace_back(field_index, int_value);
355 }
356 return true;
357}
358
359bool JsonParser::AddElement(int field_index, double double_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800360 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800361 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700362 return false;
363 }
364
365 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700366 stack_.back().vector_elements.emplace_back(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700367 } else {
368 stack_.back().elements.emplace_back(field_index, double_value);
369 }
370 return true;
371}
372
373bool JsonParser::AddElement(int field_index, const ::std::string &data) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800374 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800375 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700376 return false;
377 }
378
Alex Perrycb7da4b2019-08-28 19:35:56 -0700379 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800380 stack_.back().type.FieldElementaryType(field_index);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700381 switch (elementary_type) {
382 case flatbuffers::ET_CHAR:
383 case flatbuffers::ET_UCHAR:
384 case flatbuffers::ET_SHORT:
385 case flatbuffers::ET_USHORT:
386 case flatbuffers::ET_INT:
387 case flatbuffers::ET_UINT:
388 case flatbuffers::ET_LONG:
389 case flatbuffers::ET_ULONG:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800390 if (stack_.back().type.FieldIsEnum(field_index)) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700391 // We have an enum.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800392 const FlatbufferType type = stack_.back().type;
393 const FlatbufferType enum_type = type.FieldType(field_index);
394 CHECK(enum_type.IsEnum());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700395
Brian Silvermancf4fb662021-02-10 17:54:53 -0800396 const std::optional<int64_t> int_value = enum_type.EnumValue(data);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700397
Brian Silvermancf4fb662021-02-10 17:54:53 -0800398 if (!int_value) {
399 const std::string_view name = type.FieldName(field_index);
400 fprintf(stderr, "Enum value '%s' not found for field '%.*s'\n",
401 data.c_str(), static_cast<int>(name.size()), name.data());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700402 return false;
403 }
404
405 if (in_vector()) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800406 stack_.back().vector_elements.emplace_back(*int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700407 } else {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800408 stack_.back().elements.emplace_back(field_index, *int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700409 }
410 return true;
411 }
412 case flatbuffers::ET_UTYPE:
413 case flatbuffers::ET_BOOL:
414 case flatbuffers::ET_FLOAT:
415 case flatbuffers::ET_DOUBLE:
416 case flatbuffers::ET_STRING:
417 case flatbuffers::ET_SEQUENCE:
418 break;
419 }
420
421 if (in_vector()) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800422 stack_.back().vector_elements.emplace_back(fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700423 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800424 stack_.back().elements.emplace_back(field_index, fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700425 }
426 return true;
427}
428
Brian Silvermancf4fb662021-02-10 17:54:53 -0800429bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -0700430 ::std::vector<bool> *fields_in_use,
431 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700432 if ((*fields_in_use)[field_element.field_index]) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800433 const std::string_view name = type.FieldName(field_element.field_index);
434 fprintf(stderr, "Duplicate field: '%.*s'\n", static_cast<int>(name.size()),
435 name.data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700436 return false;
437 }
438
439 (*fields_in_use)[field_element.field_index] = true;
440
441 switch (field_element.element.type) {
442 case Element::ElementType::INT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800443 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700444 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700445 case Element::ElementType::DOUBLE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800446 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700447 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700448 case Element::ElementType::OFFSET:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800449 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700450 field_element.element.offset_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700451 }
452 return false;
453}
454
Brian Silvermancf4fb662021-02-10 17:54:53 -0800455bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
456 flatbuffers::FlatBufferBuilder *fbb
Austin Schuh43c6a352019-09-30 22:22:10 -0700457
458) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700459 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
460 static_cast<flatbuffers::voffset_t>(field_index));
461
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700462 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800463 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700464 switch (elementary_type) {
465 case flatbuffers::ET_BOOL:
Brian Silverman69069232021-11-10 12:26:52 -0800466 fbb->AddElement<bool>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700467 return true;
468 case flatbuffers::ET_CHAR:
Brian Silverman69069232021-11-10 12:26:52 -0800469 fbb->AddElement<int8_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700470 return true;
471 case flatbuffers::ET_UCHAR:
Brian Silverman69069232021-11-10 12:26:52 -0800472 fbb->AddElement<uint8_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700473 return true;
474 case flatbuffers::ET_SHORT:
Brian Silverman69069232021-11-10 12:26:52 -0800475 fbb->AddElement<int16_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700476 return true;
477 case flatbuffers::ET_USHORT:
Brian Silverman69069232021-11-10 12:26:52 -0800478 fbb->AddElement<uint16_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700479 return true;
480 case flatbuffers::ET_INT:
Brian Silverman69069232021-11-10 12:26:52 -0800481 fbb->AddElement<int32_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700482 return true;
483 case flatbuffers::ET_UINT:
Brian Silverman69069232021-11-10 12:26:52 -0800484 fbb->AddElement<uint32_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700485 return true;
486 case flatbuffers::ET_LONG:
Brian Silverman69069232021-11-10 12:26:52 -0800487 fbb->AddElement<int64_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700488 return true;
489 case flatbuffers::ET_ULONG:
Brian Silverman69069232021-11-10 12:26:52 -0800490 fbb->AddElement<uint64_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700491 return true;
492 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800493 fbb->AddElement<float>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700494 return true;
495 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800496 fbb->AddElement<double>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700497 return true;
498 case flatbuffers::ET_STRING:
499 case flatbuffers::ET_UTYPE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800500 case flatbuffers::ET_SEQUENCE: {
501 const std::string_view name = type.FieldName(field_index);
502 fprintf(stderr,
503 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
504 static_cast<int>(name.size()), name.data(),
505 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700506 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800507 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700508 };
509 return false;
510}
511
Brian Silvermancf4fb662021-02-10 17:54:53 -0800512bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
Austin Schuh43c6a352019-09-30 22:22:10 -0700513 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700514 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
515 static_cast<flatbuffers::voffset_t>(field_index));
516
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700517 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800518 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700519 switch (elementary_type) {
520 case flatbuffers::ET_UTYPE:
521 case flatbuffers::ET_BOOL:
522 case flatbuffers::ET_CHAR:
523 case flatbuffers::ET_UCHAR:
524 case flatbuffers::ET_SHORT:
525 case flatbuffers::ET_USHORT:
526 case flatbuffers::ET_INT:
527 case flatbuffers::ET_UINT:
528 case flatbuffers::ET_LONG:
529 case flatbuffers::ET_ULONG:
530 case flatbuffers::ET_STRING:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800531 case flatbuffers::ET_SEQUENCE: {
532 const std::string_view name = type.FieldName(field_index);
533 fprintf(stderr,
534 "Mismatched type for field '%.*s'. Got: double, expected %s\n",
535 static_cast<int>(name.size()), name.data(),
536 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700537 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800538 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700539 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800540 fbb->AddElement<float>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700541 return true;
542 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800543 fbb->AddElement<double>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700544 return true;
545 }
546 return false;
547}
Brian Silvermancf4fb662021-02-10 17:54:53 -0800548bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700549 flatbuffers::Offset<flatbuffers::String> offset_element,
550 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700551 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
552 static_cast<flatbuffers::voffset_t>(field_index));
553
554 // Vectors will always be Offset<>'s.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800555 if (type.FieldIsRepeating(field_index)) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700556 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700557 return true;
558 }
559
560 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800561 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700562 switch (elementary_type) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700563 case flatbuffers::ET_CHAR:
564 case flatbuffers::ET_UCHAR:
565 case flatbuffers::ET_SHORT:
566 case flatbuffers::ET_USHORT:
567 case flatbuffers::ET_INT:
568 case flatbuffers::ET_UINT:
569 case flatbuffers::ET_LONG:
570 case flatbuffers::ET_ULONG:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700571 case flatbuffers::ET_UTYPE:
572 case flatbuffers::ET_BOOL:
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700573 case flatbuffers::ET_FLOAT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800574 case flatbuffers::ET_DOUBLE: {
575 const std::string_view name = type.FieldName(field_index);
576 fprintf(stderr,
577 "Mismatched type for field '%.*s'. Got: string, expected %s\n",
578 static_cast<int>(name.size()), name.data(),
579 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700580 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800581 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700582 case flatbuffers::ET_STRING:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700583 case flatbuffers::ET_SEQUENCE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700584 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700585 return true;
586 }
587 return false;
588}
589
590bool JsonParser::FinishVector(int field_index) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800591 // Vectors have a start (unfortunately which needs to know the size)
James Kuszmaul65541cb2022-11-08 14:53:47 -0800592 const size_t inline_size = stack_.back().type.FieldInlineSize(field_index);
593 fbb_->StartVector(stack_.back().vector_elements.size(), inline_size,
594 /*align=*/inline_size);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700595
596 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800597 stack_.back().type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700598
599 // Then the data (in reverse order for some reason...)
Alex Perrycb7da4b2019-08-28 19:35:56 -0700600 for (size_t i = stack_.back().vector_elements.size(); i > 0;) {
601 const Element &element = stack_.back().vector_elements[--i];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700602 switch (element.type) {
603 case Element::ElementType::INT:
604 if (!PushElement(elementary_type, element.int_element)) return false;
605 break;
606 case Element::ElementType::DOUBLE:
607 if (!PushElement(elementary_type, element.double_element)) return false;
608 break;
609 case Element::ElementType::OFFSET:
610 if (!PushElement(elementary_type, element.offset_element)) return false;
611 break;
612 }
613 }
614
615 // Then an End which is placed into the buffer the same as any other offset.
616 stack_.back().elements.emplace_back(
617 field_index, flatbuffers::Offset<flatbuffers::String>(
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800618 fbb_->EndVector(stack_.back().vector_elements.size())));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700619 stack_.back().vector_elements.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700620 return true;
621}
622
623bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
624 int64_t int_value) {
625 switch (elementary_type) {
626 case flatbuffers::ET_BOOL:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800627 fbb_->PushElement<bool>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700628 return true;
629 case flatbuffers::ET_CHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800630 fbb_->PushElement<int8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700631 return true;
632 case flatbuffers::ET_UCHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800633 fbb_->PushElement<uint8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700634 return true;
635 case flatbuffers::ET_SHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800636 fbb_->PushElement<int16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700637 return true;
638 case flatbuffers::ET_USHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800639 fbb_->PushElement<uint16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700640 return true;
641 case flatbuffers::ET_INT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800642 fbb_->PushElement<int32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700643 return true;
644 case flatbuffers::ET_UINT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800645 fbb_->PushElement<uint32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700646 return true;
647 case flatbuffers::ET_LONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800648 fbb_->PushElement<int64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700649 return true;
650 case flatbuffers::ET_ULONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800651 fbb_->PushElement<uint64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700652 return true;
653 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800654 fbb_->PushElement<float>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700655 return true;
656 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800657 fbb_->PushElement<double>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700658 return true;
659 case flatbuffers::ET_STRING:
660 case flatbuffers::ET_UTYPE:
661 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800662 fprintf(stderr,
663 "Mismatched type for field '%s'. Got: integer, expected %s\n",
664 stack_.back().field_name.c_str(),
665 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700666 return false;
667 };
668 return false;
669}
670
671bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
672 double double_value) {
673 switch (elementary_type) {
674 case flatbuffers::ET_UTYPE:
675 case flatbuffers::ET_BOOL:
676 case flatbuffers::ET_CHAR:
677 case flatbuffers::ET_UCHAR:
678 case flatbuffers::ET_SHORT:
679 case flatbuffers::ET_USHORT:
680 case flatbuffers::ET_INT:
681 case flatbuffers::ET_UINT:
682 case flatbuffers::ET_LONG:
683 case flatbuffers::ET_ULONG:
684 case flatbuffers::ET_STRING:
685 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800686 fprintf(stderr,
687 "Mismatched type for field '%s'. Got: double, expected %s\n",
688 stack_.back().field_name.c_str(),
689 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700690 return false;
691 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800692 fbb_->PushElement<float>(double_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>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700696 return true;
697 }
698 return false;
699}
700
701bool JsonParser::PushElement(
702 flatbuffers::ElementaryType elementary_type,
703 flatbuffers::Offset<flatbuffers::String> offset_value) {
704 switch (elementary_type) {
705 case flatbuffers::ET_UTYPE:
706 case flatbuffers::ET_BOOL:
707 case flatbuffers::ET_CHAR:
708 case flatbuffers::ET_UCHAR:
709 case flatbuffers::ET_SHORT:
710 case flatbuffers::ET_USHORT:
711 case flatbuffers::ET_INT:
712 case flatbuffers::ET_UINT:
713 case flatbuffers::ET_LONG:
714 case flatbuffers::ET_ULONG:
715 case flatbuffers::ET_FLOAT:
716 case flatbuffers::ET_DOUBLE:
Austin Schuh217a9782019-12-21 23:02:50 -0800717 fprintf(stderr,
718 "Mismatched type for field '%s'. Got: sequence, expected %s\n",
719 stack_.back().field_name.c_str(),
720 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700721 return false;
722 case flatbuffers::ET_STRING:
723 case flatbuffers::ET_SEQUENCE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800724 fbb_->PushElement(offset_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700725 return true;
726 }
727 return false;
728}
729
730} // namespace
731
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800732flatbuffers::Offset<flatbuffers::Table> JsonToFlatbuffer(
Brian Silvermancf4fb662021-02-10 17:54:53 -0800733 const std::string_view data, FlatbufferType type,
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800734 flatbuffers::FlatBufferBuilder *fbb) {
735 JsonParser p(fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800736 return p.Parse(data, type);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800737}
738
Brian Silvermancf4fb662021-02-10 17:54:53 -0800739flatbuffers::DetachedBuffer JsonToFlatbuffer(const std::string_view data,
740 FlatbufferType type) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800741 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -0800742 fbb.ForceDefaults(true);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800743
744 const flatbuffers::Offset<flatbuffers::Table> result =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800745 JsonToFlatbuffer(data, type, &fbb);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800746 if (result.o != 0) {
747 fbb.Finish(result);
748
749 return fbb.Release();
750 } else {
751 // Otherwise return an empty vector.
752 return flatbuffers::DetachedBuffer();
753 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700754}
755
Austin Schuhd3936202020-04-07 20:11:07 -0700756namespace {
757
758// A visitor which manages skipping the contents of vectors that are longer than
759// a specified threshold.
760class TruncatingStringVisitor : public flatbuffers::IterationVisitor {
761 public:
762 TruncatingStringVisitor(size_t max_vector_size, std::string delimiter,
763 bool quotes, std::string indent, bool vdelimited)
764 : max_vector_size_(max_vector_size),
765 to_string_(delimiter, quotes, indent, vdelimited) {}
766 ~TruncatingStringVisitor() override {}
767
768 void StartSequence() override {
769 if (should_skip()) return;
770 to_string_.StartSequence();
771 }
772 void EndSequence() override {
773 if (should_skip()) return;
774 to_string_.EndSequence();
775 }
776 void Field(size_t field_idx, size_t set_idx, flatbuffers::ElementaryType type,
Austin Schuh7c75e582020-11-14 16:41:18 -0800777 bool is_repeating, const flatbuffers::TypeTable *type_table,
Austin Schuhd3936202020-04-07 20:11:07 -0700778 const char *name, const uint8_t *val) override {
779 if (should_skip()) return;
Austin Schuh7c75e582020-11-14 16:41:18 -0800780 to_string_.Field(field_idx, set_idx, type, is_repeating, type_table, name,
Austin Schuhd3936202020-04-07 20:11:07 -0700781 val);
782 }
783 void UType(uint8_t value, const char *name) override {
784 if (should_skip()) return;
785 to_string_.UType(value, name);
786 }
787 void Bool(bool value) override {
788 if (should_skip()) return;
789 to_string_.Bool(value);
790 }
791 void Char(int8_t value, const char *name) override {
792 if (should_skip()) return;
793 to_string_.Char(value, name);
794 }
795 void UChar(uint8_t value, const char *name) override {
796 if (should_skip()) return;
797 to_string_.UChar(value, name);
798 }
799 void Short(int16_t value, const char *name) override {
800 if (should_skip()) return;
801 to_string_.Short(value, name);
802 }
803 void UShort(uint16_t value, const char *name) override {
804 if (should_skip()) return;
805 to_string_.UShort(value, name);
806 }
807 void Int(int32_t value, const char *name) override {
808 if (should_skip()) return;
809 to_string_.Int(value, name);
810 }
811 void UInt(uint32_t value, const char *name) override {
812 if (should_skip()) return;
813 to_string_.UInt(value, name);
814 }
815 void Long(int64_t value) override {
816 if (should_skip()) return;
817 to_string_.Long(value);
818 }
819 void ULong(uint64_t value) override {
820 if (should_skip()) return;
821 to_string_.ULong(value);
822 }
823 void Float(float value) override {
824 if (should_skip()) return;
825 to_string_.Float(value);
826 }
827 void Double(double value) override {
828 if (should_skip()) return;
829 to_string_.Double(value);
830 }
831 void String(const flatbuffers::String *value) override {
832 if (should_skip()) return;
833 to_string_.String(value);
834 }
835 void Unknown(const uint8_t *value) override {
836 if (should_skip()) return;
837 to_string_.Unknown(value);
838 }
839 void Element(size_t i, flatbuffers::ElementaryType type,
840 const flatbuffers::TypeTable *type_table,
841 const uint8_t *val) override {
842 if (should_skip()) return;
843 to_string_.Element(i, type, type_table, val);
844 }
845
846 virtual void StartVector(size_t size) override {
847 if (should_skip()) {
848 ++skip_levels_;
849 return;
850 }
851 if (size > max_vector_size_) {
852 ++skip_levels_;
Austin Schuh041fe9f2021-10-16 23:01:15 -0700853 to_string_.s += "[ \"... " + std::to_string(size) + " elements ...\" ]";
Austin Schuhd3936202020-04-07 20:11:07 -0700854 return;
855 }
856 to_string_.StartVector(size);
857 }
858 virtual void EndVector() override {
859 if (should_skip()) {
860 --skip_levels_;
861 return;
862 }
863 to_string_.EndVector();
864 }
865
866 std::string &string() { return to_string_.s; }
867
868 private:
869 bool should_skip() const { return skip_levels_ > 0; }
870
871 const size_t max_vector_size_;
872 flatbuffers::ToStringVisitor to_string_;
873 int skip_levels_ = 0;
874};
875
876} // namespace
877
Austin Schuhe93d8642019-10-13 15:27:07 -0700878::std::string TableFlatbufferToJson(const flatbuffers::Table *t,
879 const ::flatbuffers::TypeTable *typetable,
Ravago Jonescf453ab2020-05-06 21:14:53 -0700880 JsonOptions json_options) {
Austin Schuhe93d8642019-10-13 15:27:07 -0700881 // It is pretty common to get passed in a nullptr when a test fails. Rather
882 // than CHECK, return a more user friendly result.
883 if (t == nullptr) {
884 return "null";
885 }
Ravago Jonescf453ab2020-05-06 21:14:53 -0700886 TruncatingStringVisitor tostring_visitor(
887 json_options.max_vector_size, json_options.multi_line ? "\n" : " ", true,
888 json_options.multi_line ? " " : "", json_options.multi_line);
Austin Schuhe93d8642019-10-13 15:27:07 -0700889 flatbuffers::IterateObject(reinterpret_cast<const uint8_t *>(t), typetable,
890 &tostring_visitor);
Austin Schuhd3936202020-04-07 20:11:07 -0700891 return tostring_visitor.string();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700892}
893
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700894} // namespace aos