blob: fa1cf6211fefa85ae5d3f12fd722ecfd5108bc55 [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 Schuh43c6a352019-09-30 22:22:10 -07007#include "aos/flatbuffer_utils.h"
Austin Schuhd7e252d2019-10-06 13:51:02 -07008#include "aos/json_tokenizer.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -07009#include "flatbuffers/flatbuffers.h"
10#include "flatbuffers/minireflect.h"
Austin Schuhe93d8642019-10-13 15:27:07 -070011#include "glog/logging.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 {
Austin Schuh3e95e5d2019-09-20 00:08:54 -070020namespace {
21
22// Class to hold one of the 3 json types for an array.
23struct Element {
24 // The type.
25 enum class ElementType { INT, DOUBLE, OFFSET };
26
27 // Constructs an Element holding an integer.
28 Element(int64_t new_int_element)
29 : int_element(new_int_element), type(ElementType::INT) {}
30 // Constructs an Element holding an double.
31 Element(double new_double_element)
32 : double_element(new_double_element), type(ElementType::DOUBLE) {}
33 // Constructs an Element holding an Offset.
34 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
35 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
36
37 // Union for the various datatypes.
38 union {
39 int64_t int_element;
40 double double_element;
41 flatbuffers::Offset<flatbuffers::String> offset_element;
42 };
43
44 // And an enum signaling which one is in use.
45 ElementType type;
46};
47
48// Structure to represent a field element.
49struct FieldElement {
50 FieldElement(int new_field_index, int64_t int_element)
51 : element(int_element), field_index(new_field_index) {}
52 FieldElement(int new_field_index, double double_element)
53 : element(double_element), field_index(new_field_index) {}
54 FieldElement(int new_field_index,
55 flatbuffers::Offset<flatbuffers::String> offset_element)
56 : element(offset_element), field_index(new_field_index) {}
57
58 // Data to write.
59 Element element;
60 // Field index. The type table which this index is for is stored outside this
61 // object.
62 int field_index;
63};
64
Austin Schuh43c6a352019-09-30 22:22:10 -070065// Adds a single element. This assumes that vectors have been dealt with
66// already. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -080067bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -070068 ::std::vector<bool> *fields_in_use,
69 flatbuffers::FlatBufferBuilder *fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -080070bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
71 flatbuffers::FlatBufferBuilder *fbb);
72bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
73 flatbuffers::FlatBufferBuilder *fbb);
74bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -070075 flatbuffers::Offset<flatbuffers::String> offset_element,
76 flatbuffers::FlatBufferBuilder *fbb);
77
Brian Silvermancf4fb662021-02-10 17:54:53 -080078// Writes an array of FieldElement (with the definition in "type") to the
79// builder. Returns the offset of the resulting table.
80flatbuffers::uoffset_t WriteTable(FlatbufferType type,
Austin Schuh43c6a352019-09-30 22:22:10 -070081 const ::std::vector<FieldElement> &elements,
82 flatbuffers::FlatBufferBuilder *fbb) {
83 // End of a nested struct! Add it.
84 const flatbuffers::uoffset_t start = fbb->StartTable();
85
Brian Silvermancf4fb662021-02-10 17:54:53 -080086 ::std::vector<bool> fields_in_use(type.NumberFields(), false);
Austin Schuh43c6a352019-09-30 22:22:10 -070087
88 for (const FieldElement &field_element : elements) {
Brian Silvermancf4fb662021-02-10 17:54:53 -080089 AddSingleElement(type, field_element, &fields_in_use, fbb);
Austin Schuh43c6a352019-09-30 22:22:10 -070090 }
91
92 return fbb->EndTable(start);
93}
94
Austin Schuh3e95e5d2019-09-20 00:08:54 -070095// Class to parse JSON into a flatbuffer.
96//
97// The basic strategy is that we need to do everything backwards. So we need to
98// build up what we need to do fully in memory, then do it.
99//
100// The driver for this is that strings need to be fully created before the
101// tables that use them. Same for sub messages. But, we only know we have them
Austin Schuh43c6a352019-09-30 22:22:10 -0700102// all when the structure ends. So, store each sub message in a
103// FieldElement and put them in the table at the end when we finish up
104// each message. Same goes for vectors.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700105class JsonParser {
106 public:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800107 JsonParser(flatbuffers::FlatBufferBuilder *fbb) : fbb_(fbb) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700108 ~JsonParser() {}
109
110 // Parses the json into a flatbuffer. Returns either an empty vector on
111 // error, or a vector with the flatbuffer data in it.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800112 flatbuffers::Offset<flatbuffers::Table> Parse(const std::string_view data,
113 FlatbufferType type) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700114 flatbuffers::uoffset_t end = 0;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800115 bool result = DoParse(type, data, &end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700116
117 if (result) {
118 // On success, finish the table and build the vector.
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800119 return flatbuffers::Offset<flatbuffers::Table>(end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700120 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800121 return flatbuffers::Offset<flatbuffers::Table>(0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700122 }
123 }
124
125 private:
126 // Setters and getters for in_vector (at the current level of the stack)
127 bool in_vector() const { return stack_.back().in_vector; }
128 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
129
130 // Parses the flatbuffer. This is a second method so we can do easier
131 // cleanup at the top level. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800132 bool DoParse(FlatbufferType type, const std::string_view data,
133 flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700134
135 // Adds *_value for the provided field. If we are in a vector, queues the
Alex Perrycb7da4b2019-08-28 19:35:56 -0700136 // data up in vector_elements. Returns true on success.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700137 bool AddElement(int field_index, int64_t int_value);
138 bool AddElement(int field_index, double double_value);
139 bool AddElement(int field_index, const ::std::string &data);
140
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700141 // Finishes a vector for the provided field index. Returns true on success.
142 bool FinishVector(int field_index);
143
144 // Pushes an element as part of a vector. Returns true on success.
145 bool PushElement(flatbuffers::ElementaryType elementary_type,
146 int64_t int_value);
147 bool PushElement(flatbuffers::ElementaryType elementary_type,
148 double double_value);
149 bool PushElement(flatbuffers::ElementaryType elementary_type,
150 flatbuffers::Offset<flatbuffers::String> offset_value);
151
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800152 flatbuffers::FlatBufferBuilder *fbb_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700153
154 // This holds the state information that is needed as you recurse into
155 // nested structures.
156 struct FlatBufferContext {
157 // Type of the current type.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800158 FlatbufferType type;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700159 // If true, we are parsing a vector.
160 bool in_vector;
161 // The field index of the current field.
162 int field_index;
163 // Name of the current field.
164 ::std::string field_name;
165
166 // Field elements that need to be inserted.
167 ::std::vector<FieldElement> elements;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700168
169 // For scalar types (not strings, and not nested tables), the vector ends
170 // up being implemented as a start and end, and a block of data. So we
171 // can't just push offsets in as we go. We either need to reproduce the
172 // logic inside flatbuffers, or build up vectors of the data. Vectors will
173 // be a bit of extra stack space, but whatever.
174 //
175 // Strings and nested structures are vectors of offsets.
176 // into the vector. Once you get to the end, you build up a vector and
177 // push that into the field.
178 ::std::vector<Element> vector_elements;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700179 };
180 ::std::vector<FlatBufferContext> stack_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700181};
182
Brian Silvermancf4fb662021-02-10 17:54:53 -0800183bool JsonParser::DoParse(FlatbufferType type, const std::string_view data,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700184 flatbuffers::uoffset_t *table_end) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800185 ::std::vector<FlatbufferType> stack;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700186
187 Tokenizer t(data);
188
189 // Main loop. Run until we get an end.
190 while (true) {
191 Tokenizer::TokenType token = t.Next();
192
193 switch (token) {
194 case Tokenizer::TokenType::kEnd:
195 if (stack_.size() != 0) {
Austin Schuh217a9782019-12-21 23:02:50 -0800196 fprintf(stderr, "Failed to unwind stack all the way\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700197 return false;
198 } else {
199 return true;
200 }
201 break;
202 case Tokenizer::TokenType::kError:
203 return false;
204 break;
205
206 case Tokenizer::TokenType::kStartObject: // {
207 if (stack_.size() == 0) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800208 stack_.push_back({type, false, -1, "", {}, {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700209 } else {
210 int field_index = stack_.back().field_index;
211
Brian Silvermancf4fb662021-02-10 17:54:53 -0800212 if (!stack_.back().type.FieldIsSequence(field_index)) {
Austin Schuh217a9782019-12-21 23:02:50 -0800213 fprintf(stderr, "Field '%s' is not a sequence\n",
214 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700215 return false;
216 }
217
James Kuszmaulbb60dfd2023-01-05 17:13:11 -0800218 if (in_vector() != stack_.back().type.FieldIsRepeating(field_index)) {
219 fprintf(stderr,
220 "Field '%s' is%s supposed to be a vector, but is a %s.\n",
221 stack_.back().field_name.c_str(), in_vector() ? " not" : "",
222 in_vector() ? "vector" : "bare object");
223 return false;
224 }
225
Brian Silvermancf4fb662021-02-10 17:54:53 -0800226 stack_.push_back({stack_.back().type.FieldType(field_index),
227 false,
228 -1,
229 "",
230 {},
231 {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700232 }
233 break;
234 case Tokenizer::TokenType::kEndObject: // }
235 if (stack_.size() == 0) {
236 // Somehow we popped more than we pushed. Error.
Austin Schuh217a9782019-12-21 23:02:50 -0800237 fprintf(stderr, "Empty stack\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700238 return false;
239 } else {
240 // End of a nested struct! Add it.
Austin Schuhd3936202020-04-07 20:11:07 -0700241 const flatbuffers::uoffset_t end =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800242 WriteTable(stack_.back().type, stack_.back().elements, fbb_);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700243
244 // We now want to talk about the parent structure. Pop the child.
245 stack_.pop_back();
246
247 if (stack_.size() == 0) {
248 // Instead of queueing it up in the stack, return it through the
249 // passed in variable.
250 *table_end = end;
251 } else {
252 // And now we can add it.
253 const int field_index = stack_.back().field_index;
254
255 // Do the right thing if we are in a vector.
256 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700257 stack_.back().vector_elements.emplace_back(
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700258 flatbuffers::Offset<flatbuffers::String>(end));
259 } else {
260 stack_.back().elements.emplace_back(
261 field_index, flatbuffers::Offset<flatbuffers::String>(end));
262 }
263 }
264 }
265 break;
266
267 case Tokenizer::TokenType::kStartArray: // [
268 if (stack_.size() == 0) {
269 // We don't support an array of structs at the root level.
270 return false;
271 }
272 // Sanity check that we aren't trying to make a vector of vectors.
273 if (in_vector()) {
274 return false;
275 }
276 set_in_vector(true);
277
278 break;
279 case Tokenizer::TokenType::kEndArray: { // ]
280 if (!in_vector()) {
281 return false;
282 }
283
284 const int field_index = stack_.back().field_index;
285
286 if (!FinishVector(field_index)) return false;
287
288 set_in_vector(false);
289 } break;
290
291 case Tokenizer::TokenType::kTrueValue: // true
292 case Tokenizer::TokenType::kFalseValue: // false
293 case Tokenizer::TokenType::kNumberValue: {
294 bool is_int = true;
295 double double_value;
296 long long int_value;
297 if (token == Tokenizer::TokenType::kTrueValue) {
298 int_value = 1;
299 } else if (token == Tokenizer::TokenType::kFalseValue) {
300 int_value = 0;
301 } else if (!t.FieldAsInt(&int_value)) {
302 if (t.FieldAsDouble(&double_value)) {
303 is_int = false;
304 } else {
305 fprintf(stderr, "Got a invalid number '%s'\n",
306 t.field_value().c_str());
307 return false;
308 }
309 }
310
311 const int field_index = stack_.back().field_index;
312
313 if (is_int) {
314 // No need to get too stressed about bool vs int. Convert them all.
315 int64_t val = int_value;
316 if (!AddElement(field_index, val)) return false;
317 } else {
318 if (!AddElement(field_index, double_value)) return false;
319 }
320 } break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700321 case Tokenizer::TokenType::kStringValue: // string value
322 {
323 const int field_index = stack_.back().field_index;
324
325 if (!AddElement(field_index, t.field_value())) return false;
326 } break;
327 case Tokenizer::TokenType::kField: // field name
328 {
329 stack_.back().field_name = t.field_name();
Brian Silvermancf4fb662021-02-10 17:54:53 -0800330 stack_.back().field_index =
331 stack_.back().type.FieldIndex(stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700332
333 if (stack_.back().field_index == -1) {
Austin Schuh217a9782019-12-21 23:02:50 -0800334 fprintf(stderr, "Invalid field name '%s'\n",
335 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700336 return false;
337 }
338 } break;
339 }
340 }
341 return false;
342}
343
344bool JsonParser::AddElement(int field_index, int64_t int_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800345 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800346 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700347 return false;
348 }
349
350 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700351 stack_.back().vector_elements.emplace_back(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700352 } else {
353 stack_.back().elements.emplace_back(field_index, int_value);
354 }
355 return true;
356}
357
358bool JsonParser::AddElement(int field_index, double double_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800359 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
Austin Schuh217a9782019-12-21 23:02:50 -0800360 fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700361 return false;
362 }
363
364 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700365 stack_.back().vector_elements.emplace_back(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700366 } else {
367 stack_.back().elements.emplace_back(field_index, double_value);
368 }
369 return true;
370}
371
372bool JsonParser::AddElement(int field_index, const ::std::string &data) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800373 if (stack_.back().type.FieldIsRepeating(field_index) != 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
Alex Perrycb7da4b2019-08-28 19:35:56 -0700378 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800379 stack_.back().type.FieldElementaryType(field_index);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700380 switch (elementary_type) {
381 case flatbuffers::ET_CHAR:
382 case flatbuffers::ET_UCHAR:
383 case flatbuffers::ET_SHORT:
384 case flatbuffers::ET_USHORT:
385 case flatbuffers::ET_INT:
386 case flatbuffers::ET_UINT:
387 case flatbuffers::ET_LONG:
388 case flatbuffers::ET_ULONG:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800389 if (stack_.back().type.FieldIsEnum(field_index)) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700390 // We have an enum.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800391 const FlatbufferType type = stack_.back().type;
392 const FlatbufferType enum_type = type.FieldType(field_index);
393 CHECK(enum_type.IsEnum());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700394
Brian Silvermancf4fb662021-02-10 17:54:53 -0800395 const std::optional<int64_t> int_value = enum_type.EnumValue(data);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700396
Brian Silvermancf4fb662021-02-10 17:54:53 -0800397 if (!int_value) {
398 const std::string_view name = type.FieldName(field_index);
399 fprintf(stderr, "Enum value '%s' not found for field '%.*s'\n",
400 data.c_str(), static_cast<int>(name.size()), name.data());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700401 return false;
402 }
403
404 if (in_vector()) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800405 stack_.back().vector_elements.emplace_back(*int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700406 } else {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800407 stack_.back().elements.emplace_back(field_index, *int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700408 }
409 return true;
410 }
411 case flatbuffers::ET_UTYPE:
412 case flatbuffers::ET_BOOL:
413 case flatbuffers::ET_FLOAT:
414 case flatbuffers::ET_DOUBLE:
415 case flatbuffers::ET_STRING:
416 case flatbuffers::ET_SEQUENCE:
417 break;
418 }
419
420 if (in_vector()) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800421 stack_.back().vector_elements.emplace_back(fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700422 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800423 stack_.back().elements.emplace_back(field_index, fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700424 }
425 return true;
426}
427
Brian Silvermancf4fb662021-02-10 17:54:53 -0800428bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -0700429 ::std::vector<bool> *fields_in_use,
430 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700431 if ((*fields_in_use)[field_element.field_index]) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800432 const std::string_view name = type.FieldName(field_element.field_index);
433 fprintf(stderr, "Duplicate field: '%.*s'\n", static_cast<int>(name.size()),
434 name.data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700435 return false;
436 }
437
438 (*fields_in_use)[field_element.field_index] = true;
439
440 switch (field_element.element.type) {
441 case Element::ElementType::INT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800442 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700443 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700444 case Element::ElementType::DOUBLE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800445 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700446 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700447 case Element::ElementType::OFFSET:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800448 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700449 field_element.element.offset_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700450 }
451 return false;
452}
453
Brian Silvermancf4fb662021-02-10 17:54:53 -0800454bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
455 flatbuffers::FlatBufferBuilder *fbb
Austin Schuh43c6a352019-09-30 22:22:10 -0700456
457) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700458 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
459 static_cast<flatbuffers::voffset_t>(field_index));
460
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700461 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800462 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700463 switch (elementary_type) {
464 case flatbuffers::ET_BOOL:
Brian Silverman69069232021-11-10 12:26:52 -0800465 fbb->AddElement<bool>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700466 return true;
467 case flatbuffers::ET_CHAR:
Brian Silverman69069232021-11-10 12:26:52 -0800468 fbb->AddElement<int8_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700469 return true;
470 case flatbuffers::ET_UCHAR:
Brian Silverman69069232021-11-10 12:26:52 -0800471 fbb->AddElement<uint8_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700472 return true;
473 case flatbuffers::ET_SHORT:
Brian Silverman69069232021-11-10 12:26:52 -0800474 fbb->AddElement<int16_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700475 return true;
476 case flatbuffers::ET_USHORT:
Brian Silverman69069232021-11-10 12:26:52 -0800477 fbb->AddElement<uint16_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700478 return true;
479 case flatbuffers::ET_INT:
Brian Silverman69069232021-11-10 12:26:52 -0800480 fbb->AddElement<int32_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700481 return true;
482 case flatbuffers::ET_UINT:
Brian Silverman69069232021-11-10 12:26:52 -0800483 fbb->AddElement<uint32_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700484 return true;
485 case flatbuffers::ET_LONG:
Brian Silverman69069232021-11-10 12:26:52 -0800486 fbb->AddElement<int64_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700487 return true;
488 case flatbuffers::ET_ULONG:
Brian Silverman69069232021-11-10 12:26:52 -0800489 fbb->AddElement<uint64_t>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700490 return true;
491 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800492 fbb->AddElement<float>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700493 return true;
494 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800495 fbb->AddElement<double>(field_offset, int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700496 return true;
497 case flatbuffers::ET_STRING:
498 case flatbuffers::ET_UTYPE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800499 case flatbuffers::ET_SEQUENCE: {
500 const std::string_view name = type.FieldName(field_index);
501 fprintf(stderr,
502 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
503 static_cast<int>(name.size()), name.data(),
504 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700505 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800506 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700507 };
508 return false;
509}
510
Brian Silvermancf4fb662021-02-10 17:54:53 -0800511bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
Austin Schuh43c6a352019-09-30 22:22:10 -0700512 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700513 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
514 static_cast<flatbuffers::voffset_t>(field_index));
515
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700516 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800517 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700518 switch (elementary_type) {
519 case flatbuffers::ET_UTYPE:
520 case flatbuffers::ET_BOOL:
521 case flatbuffers::ET_CHAR:
522 case flatbuffers::ET_UCHAR:
523 case flatbuffers::ET_SHORT:
524 case flatbuffers::ET_USHORT:
525 case flatbuffers::ET_INT:
526 case flatbuffers::ET_UINT:
527 case flatbuffers::ET_LONG:
528 case flatbuffers::ET_ULONG:
529 case flatbuffers::ET_STRING:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800530 case flatbuffers::ET_SEQUENCE: {
531 const std::string_view name = type.FieldName(field_index);
532 fprintf(stderr,
533 "Mismatched type for field '%.*s'. Got: double, expected %s\n",
534 static_cast<int>(name.size()), name.data(),
535 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700536 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800537 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700538 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800539 fbb->AddElement<float>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700540 return true;
541 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800542 fbb->AddElement<double>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700543 return true;
544 }
545 return false;
546}
Brian Silvermancf4fb662021-02-10 17:54:53 -0800547bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700548 flatbuffers::Offset<flatbuffers::String> offset_element,
549 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700550 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
551 static_cast<flatbuffers::voffset_t>(field_index));
552
553 // Vectors will always be Offset<>'s.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800554 if (type.FieldIsRepeating(field_index)) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700555 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700556 return true;
557 }
558
559 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800560 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700561 switch (elementary_type) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700562 case flatbuffers::ET_CHAR:
563 case flatbuffers::ET_UCHAR:
564 case flatbuffers::ET_SHORT:
565 case flatbuffers::ET_USHORT:
566 case flatbuffers::ET_INT:
567 case flatbuffers::ET_UINT:
568 case flatbuffers::ET_LONG:
569 case flatbuffers::ET_ULONG:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700570 case flatbuffers::ET_UTYPE:
571 case flatbuffers::ET_BOOL:
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700572 case flatbuffers::ET_FLOAT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800573 case flatbuffers::ET_DOUBLE: {
574 const std::string_view name = type.FieldName(field_index);
575 fprintf(stderr,
576 "Mismatched type for field '%.*s'. Got: string, expected %s\n",
577 static_cast<int>(name.size()), name.data(),
578 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700579 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800580 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700581 case flatbuffers::ET_STRING:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700582 case flatbuffers::ET_SEQUENCE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700583 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700584 return true;
585 }
586 return false;
587}
588
589bool JsonParser::FinishVector(int field_index) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800590 // Vectors have a start (unfortunately which needs to know the size)
James Kuszmaul65541cb2022-11-08 14:53:47 -0800591 const size_t inline_size = stack_.back().type.FieldInlineSize(field_index);
592 fbb_->StartVector(stack_.back().vector_elements.size(), inline_size,
593 /*align=*/inline_size);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700594
595 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800596 stack_.back().type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700597
598 // Then the data (in reverse order for some reason...)
Alex Perrycb7da4b2019-08-28 19:35:56 -0700599 for (size_t i = stack_.back().vector_elements.size(); i > 0;) {
600 const Element &element = stack_.back().vector_elements[--i];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700601 switch (element.type) {
602 case Element::ElementType::INT:
603 if (!PushElement(elementary_type, element.int_element)) return false;
604 break;
605 case Element::ElementType::DOUBLE:
606 if (!PushElement(elementary_type, element.double_element)) return false;
607 break;
608 case Element::ElementType::OFFSET:
609 if (!PushElement(elementary_type, element.offset_element)) return false;
610 break;
611 }
612 }
613
614 // Then an End which is placed into the buffer the same as any other offset.
615 stack_.back().elements.emplace_back(
616 field_index, flatbuffers::Offset<flatbuffers::String>(
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800617 fbb_->EndVector(stack_.back().vector_elements.size())));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700618 stack_.back().vector_elements.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700619 return true;
620}
621
622bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
623 int64_t int_value) {
624 switch (elementary_type) {
625 case flatbuffers::ET_BOOL:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800626 fbb_->PushElement<bool>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700627 return true;
628 case flatbuffers::ET_CHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800629 fbb_->PushElement<int8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700630 return true;
631 case flatbuffers::ET_UCHAR:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800632 fbb_->PushElement<uint8_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700633 return true;
634 case flatbuffers::ET_SHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800635 fbb_->PushElement<int16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700636 return true;
637 case flatbuffers::ET_USHORT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800638 fbb_->PushElement<uint16_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700639 return true;
640 case flatbuffers::ET_INT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800641 fbb_->PushElement<int32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700642 return true;
643 case flatbuffers::ET_UINT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800644 fbb_->PushElement<uint32_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700645 return true;
646 case flatbuffers::ET_LONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800647 fbb_->PushElement<int64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700648 return true;
649 case flatbuffers::ET_ULONG:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800650 fbb_->PushElement<uint64_t>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700651 return true;
652 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800653 fbb_->PushElement<float>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700654 return true;
655 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800656 fbb_->PushElement<double>(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700657 return true;
658 case flatbuffers::ET_STRING:
659 case flatbuffers::ET_UTYPE:
660 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800661 fprintf(stderr,
662 "Mismatched type for field '%s'. Got: integer, expected %s\n",
663 stack_.back().field_name.c_str(),
664 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700665 return false;
666 };
667 return false;
668}
669
670bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
671 double double_value) {
672 switch (elementary_type) {
673 case flatbuffers::ET_UTYPE:
674 case flatbuffers::ET_BOOL:
675 case flatbuffers::ET_CHAR:
676 case flatbuffers::ET_UCHAR:
677 case flatbuffers::ET_SHORT:
678 case flatbuffers::ET_USHORT:
679 case flatbuffers::ET_INT:
680 case flatbuffers::ET_UINT:
681 case flatbuffers::ET_LONG:
682 case flatbuffers::ET_ULONG:
683 case flatbuffers::ET_STRING:
684 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800685 fprintf(stderr,
686 "Mismatched type for field '%s'. Got: double, expected %s\n",
687 stack_.back().field_name.c_str(),
688 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700689 return false;
690 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800691 fbb_->PushElement<float>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700692 return true;
693 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800694 fbb_->PushElement<double>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700695 return true;
696 }
697 return false;
698}
699
700bool JsonParser::PushElement(
701 flatbuffers::ElementaryType elementary_type,
702 flatbuffers::Offset<flatbuffers::String> offset_value) {
703 switch (elementary_type) {
704 case flatbuffers::ET_UTYPE:
705 case flatbuffers::ET_BOOL:
706 case flatbuffers::ET_CHAR:
707 case flatbuffers::ET_UCHAR:
708 case flatbuffers::ET_SHORT:
709 case flatbuffers::ET_USHORT:
710 case flatbuffers::ET_INT:
711 case flatbuffers::ET_UINT:
712 case flatbuffers::ET_LONG:
713 case flatbuffers::ET_ULONG:
714 case flatbuffers::ET_FLOAT:
715 case flatbuffers::ET_DOUBLE:
Austin Schuh217a9782019-12-21 23:02:50 -0800716 fprintf(stderr,
717 "Mismatched type for field '%s'. Got: sequence, expected %s\n",
718 stack_.back().field_name.c_str(),
719 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700720 return false;
721 case flatbuffers::ET_STRING:
722 case flatbuffers::ET_SEQUENCE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800723 fbb_->PushElement(offset_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700724 return true;
725 }
726 return false;
727}
728
729} // namespace
730
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800731flatbuffers::Offset<flatbuffers::Table> JsonToFlatbuffer(
Brian Silvermancf4fb662021-02-10 17:54:53 -0800732 const std::string_view data, FlatbufferType type,
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800733 flatbuffers::FlatBufferBuilder *fbb) {
734 JsonParser p(fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800735 return p.Parse(data, type);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800736}
737
Brian Silvermancf4fb662021-02-10 17:54:53 -0800738flatbuffers::DetachedBuffer JsonToFlatbuffer(const std::string_view data,
739 FlatbufferType type) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800740 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -0800741 fbb.ForceDefaults(true);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800742
743 const flatbuffers::Offset<flatbuffers::Table> result =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800744 JsonToFlatbuffer(data, type, &fbb);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800745 if (result.o != 0) {
746 fbb.Finish(result);
747
748 return fbb.Release();
749 } else {
750 // Otherwise return an empty vector.
751 return flatbuffers::DetachedBuffer();
752 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700753}
754
Austin Schuhd3936202020-04-07 20:11:07 -0700755namespace {
756
757// A visitor which manages skipping the contents of vectors that are longer than
758// a specified threshold.
759class TruncatingStringVisitor : public flatbuffers::IterationVisitor {
760 public:
761 TruncatingStringVisitor(size_t max_vector_size, std::string delimiter,
762 bool quotes, std::string indent, bool vdelimited)
763 : max_vector_size_(max_vector_size),
764 to_string_(delimiter, quotes, indent, vdelimited) {}
765 ~TruncatingStringVisitor() override {}
766
767 void StartSequence() override {
768 if (should_skip()) return;
769 to_string_.StartSequence();
770 }
771 void EndSequence() override {
772 if (should_skip()) return;
773 to_string_.EndSequence();
774 }
775 void Field(size_t field_idx, size_t set_idx, flatbuffers::ElementaryType type,
Austin Schuh7c75e582020-11-14 16:41:18 -0800776 bool is_repeating, const flatbuffers::TypeTable *type_table,
Austin Schuhd3936202020-04-07 20:11:07 -0700777 const char *name, const uint8_t *val) override {
778 if (should_skip()) return;
Austin Schuh7c75e582020-11-14 16:41:18 -0800779 to_string_.Field(field_idx, set_idx, type, is_repeating, type_table, name,
Austin Schuhd3936202020-04-07 20:11:07 -0700780 val);
781 }
782 void UType(uint8_t value, const char *name) override {
783 if (should_skip()) return;
784 to_string_.UType(value, name);
785 }
786 void Bool(bool value) override {
787 if (should_skip()) return;
788 to_string_.Bool(value);
789 }
790 void Char(int8_t value, const char *name) override {
791 if (should_skip()) return;
792 to_string_.Char(value, name);
793 }
794 void UChar(uint8_t value, const char *name) override {
795 if (should_skip()) return;
796 to_string_.UChar(value, name);
797 }
798 void Short(int16_t value, const char *name) override {
799 if (should_skip()) return;
800 to_string_.Short(value, name);
801 }
802 void UShort(uint16_t value, const char *name) override {
803 if (should_skip()) return;
804 to_string_.UShort(value, name);
805 }
806 void Int(int32_t value, const char *name) override {
807 if (should_skip()) return;
808 to_string_.Int(value, name);
809 }
810 void UInt(uint32_t value, const char *name) override {
811 if (should_skip()) return;
812 to_string_.UInt(value, name);
813 }
814 void Long(int64_t value) override {
815 if (should_skip()) return;
816 to_string_.Long(value);
817 }
818 void ULong(uint64_t value) override {
819 if (should_skip()) return;
820 to_string_.ULong(value);
821 }
822 void Float(float value) override {
823 if (should_skip()) return;
824 to_string_.Float(value);
825 }
826 void Double(double value) override {
827 if (should_skip()) return;
828 to_string_.Double(value);
829 }
830 void String(const flatbuffers::String *value) override {
831 if (should_skip()) return;
832 to_string_.String(value);
833 }
834 void Unknown(const uint8_t *value) override {
835 if (should_skip()) return;
836 to_string_.Unknown(value);
837 }
838 void Element(size_t i, flatbuffers::ElementaryType type,
839 const flatbuffers::TypeTable *type_table,
840 const uint8_t *val) override {
841 if (should_skip()) return;
842 to_string_.Element(i, type, type_table, val);
843 }
844
845 virtual void StartVector(size_t size) override {
846 if (should_skip()) {
847 ++skip_levels_;
848 return;
849 }
850 if (size > max_vector_size_) {
851 ++skip_levels_;
Austin Schuh041fe9f2021-10-16 23:01:15 -0700852 to_string_.s += "[ \"... " + std::to_string(size) + " elements ...\" ]";
Austin Schuhd3936202020-04-07 20:11:07 -0700853 return;
854 }
855 to_string_.StartVector(size);
856 }
857 virtual void EndVector() override {
858 if (should_skip()) {
859 --skip_levels_;
860 return;
861 }
862 to_string_.EndVector();
863 }
864
865 std::string &string() { return to_string_.s; }
866
867 private:
868 bool should_skip() const { return skip_levels_ > 0; }
869
870 const size_t max_vector_size_;
871 flatbuffers::ToStringVisitor to_string_;
872 int skip_levels_ = 0;
873};
874
875} // namespace
876
Austin Schuhe93d8642019-10-13 15:27:07 -0700877::std::string TableFlatbufferToJson(const flatbuffers::Table *t,
878 const ::flatbuffers::TypeTable *typetable,
Ravago Jonescf453ab2020-05-06 21:14:53 -0700879 JsonOptions json_options) {
Austin Schuhe93d8642019-10-13 15:27:07 -0700880 // It is pretty common to get passed in a nullptr when a test fails. Rather
881 // than CHECK, return a more user friendly result.
882 if (t == nullptr) {
883 return "null";
884 }
Ravago Jonescf453ab2020-05-06 21:14:53 -0700885 TruncatingStringVisitor tostring_visitor(
886 json_options.max_vector_size, json_options.multi_line ? "\n" : " ", true,
887 json_options.multi_line ? " " : "", json_options.multi_line);
Austin Schuhe93d8642019-10-13 15:27:07 -0700888 flatbuffers::IterateObject(reinterpret_cast<const uint8_t *>(t), typetable,
889 &tostring_visitor);
Austin Schuhd3936202020-04-07 20:11:07 -0700890 return tostring_visitor.string();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700891}
892
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700893} // namespace aos