blob: 2a19557fbbe4faaab414be24a9d7df5866a35477 [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 Schuh99f7c6a2024-06-25 22:07:44 -07007#include "absl/log/check.h"
8#include "absl/log/log.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -07009#include "flatbuffers/flatbuffers.h"
10#include "flatbuffers/minireflect.h"
11
Philipp Schrader790cb542023-07-05 21:06:52 -070012#include "aos/flatbuffer_utils.h"
13#include "aos/json_tokenizer.h"
14
Austin Schuh3e95e5d2019-09-20 00:08:54 -070015// TODO(austin): Can we just do an Offset<void> ? It doesn't matter, so maybe
16// just say that.
17//
18// TODO(austin): I've yet to see how to create an ET_UTYPE, so I don't know what
19// one is and how to test it. So everything rejects it.
20
21namespace aos {
Austin Schuh3e95e5d2019-09-20 00:08:54 -070022namespace {
23
24// Class to hold one of the 3 json types for an array.
25struct Element {
26 // The type.
James Kuszmaul768c4682023-10-12 21:07:16 -070027 enum class ElementType { INT, DOUBLE, OFFSET, STRUCT };
Austin Schuh3e95e5d2019-09-20 00:08:54 -070028
29 // Constructs an Element holding an integer.
James Kuszmaul768c4682023-10-12 21:07:16 -070030 Element(absl::int128 new_int_element)
Austin Schuh3e95e5d2019-09-20 00:08:54 -070031 : int_element(new_int_element), type(ElementType::INT) {}
32 // Constructs an Element holding an double.
33 Element(double new_double_element)
34 : double_element(new_double_element), type(ElementType::DOUBLE) {}
35 // Constructs an Element holding an Offset.
36 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
37 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
James Kuszmaul768c4682023-10-12 21:07:16 -070038 // Constructs an Element holding a struct.
39 Element(std::vector<uint8_t> struct_data)
40 : /*initialize the union member to keep the compiler happy*/ int_element(
41 0),
42 struct_data(std::move(struct_data)),
43 type(ElementType::STRUCT) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -070044
45 // Union for the various datatypes.
46 union {
James Kuszmaul768c4682023-10-12 21:07:16 -070047 absl::int128 int_element;
Austin Schuh3e95e5d2019-09-20 00:08:54 -070048 double double_element;
49 flatbuffers::Offset<flatbuffers::String> offset_element;
50 };
James Kuszmaul768c4682023-10-12 21:07:16 -070051 // Because we can't know the maximum size of any potential structs at
52 // compile-time, we will use a vector to store the vector data inline.
53 // If you were to do a reinterpret_cast<StructType*>(struct_data.data()) then
54 // you would have an instance of the struct in question.
55 std::vector<uint8_t> struct_data;
Austin Schuh3e95e5d2019-09-20 00:08:54 -070056
57 // And an enum signaling which one is in use.
58 ElementType type;
59};
60
61// Structure to represent a field element.
62struct FieldElement {
James Kuszmaul768c4682023-10-12 21:07:16 -070063 FieldElement(int new_field_index, absl::int128 int_element)
Austin Schuh3e95e5d2019-09-20 00:08:54 -070064 : 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) {}
James Kuszmaul768c4682023-10-12 21:07:16 -070070 FieldElement(int new_field_index, const Element &element)
71 : element(element), field_index(new_field_index) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -070072
73 // Data to write.
74 Element element;
75 // Field index. The type table which this index is for is stored outside this
76 // object.
77 int field_index;
78};
79
Austin Schuh43c6a352019-09-30 22:22:10 -070080// Adds a single element. This assumes that vectors have been dealt with
81// already. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -080082bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -070083 ::std::vector<bool> *fields_in_use,
84 flatbuffers::FlatBufferBuilder *fbb);
James Kuszmaul768c4682023-10-12 21:07:16 -070085bool AddSingleElement(FlatbufferType type, int field_index,
86 absl::int128 int_value,
Brian Silvermancf4fb662021-02-10 17:54:53 -080087 flatbuffers::FlatBufferBuilder *fbb);
88bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
89 flatbuffers::FlatBufferBuilder *fbb);
90bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -070091 flatbuffers::Offset<flatbuffers::String> offset_element,
92 flatbuffers::FlatBufferBuilder *fbb);
James Kuszmaul768c4682023-10-12 21:07:16 -070093bool AddSingleElement(FlatbufferType type, int field_index,
94 const std::vector<uint8_t> &struct_data,
95 flatbuffers::FlatBufferBuilder *fbb);
96
97template <typename T, typename U>
98void SetMemory(U value, uint8_t *destination) {
99 // destination may be poorly aligned. As such, we should not simply do
100 // *reinterpret_cast<T*>(destination) = value directly.
101 const T casted = static_cast<T>(value);
102 memcpy(destination, &casted, sizeof(T));
103}
104
105bool SetStructElement(FlatbufferType type, int field_index, absl::int128 value,
106 uint8_t *destination) {
107 const flatbuffers::ElementaryType elementary_type =
108 type.FieldElementaryType(field_index);
109 switch (elementary_type) {
110 case flatbuffers::ET_CHAR:
111 SetMemory<int8_t>(value, destination);
112 break;
113 case flatbuffers::ET_UCHAR:
114 SetMemory<uint8_t>(value, destination);
115 break;
116 case flatbuffers::ET_SHORT:
117 SetMemory<int16_t>(value, destination);
118 break;
119 case flatbuffers::ET_USHORT:
120 SetMemory<uint16_t>(value, destination);
121 break;
122 case flatbuffers::ET_INT:
123 SetMemory<int32_t>(value, destination);
124 break;
125 case flatbuffers::ET_UINT:
126 SetMemory<uint32_t>(value, destination);
127 break;
128 case flatbuffers::ET_LONG:
129 SetMemory<int64_t>(value, destination);
130 break;
131 case flatbuffers::ET_ULONG:
132 SetMemory<uint64_t>(value, destination);
133 break;
134 case flatbuffers::ET_BOOL:
135 SetMemory<bool>(value, destination);
136 break;
137 case flatbuffers::ET_FLOAT:
138 SetMemory<float>(value, destination);
139 break;
140 case flatbuffers::ET_DOUBLE:
141 SetMemory<double>(value, destination);
142 break;
143 case flatbuffers::ET_STRING:
144 case flatbuffers::ET_UTYPE:
145 case flatbuffers::ET_SEQUENCE: {
146 const std::string_view name = type.FieldName(field_index);
147 fprintf(stderr,
148 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
149 static_cast<int>(name.size()), name.data(),
150 ElementaryTypeName(elementary_type));
151 return false;
152 }
153 }
154 return true;
155}
156
157bool SetStructElement(FlatbufferType type, int field_index, double value,
158 uint8_t *destination) {
159 const flatbuffers::ElementaryType elementary_type =
160 type.FieldElementaryType(field_index);
161 switch (elementary_type) {
162 case flatbuffers::ET_FLOAT:
163 SetMemory<float>(value, destination);
164 break;
165 case flatbuffers::ET_DOUBLE:
166 SetMemory<double>(value, destination);
167 break;
168 case flatbuffers::ET_CHAR:
169 case flatbuffers::ET_UCHAR:
170 case flatbuffers::ET_SHORT:
171 case flatbuffers::ET_USHORT:
172 case flatbuffers::ET_INT:
173 case flatbuffers::ET_UINT:
174 case flatbuffers::ET_LONG:
175 case flatbuffers::ET_ULONG:
176 case flatbuffers::ET_BOOL:
177 case flatbuffers::ET_STRING:
178 case flatbuffers::ET_UTYPE:
179 case flatbuffers::ET_SEQUENCE: {
180 const std::string_view name = type.FieldName(field_index);
181 fprintf(stderr,
182 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
183 static_cast<int>(name.size()), name.data(),
184 ElementaryTypeName(elementary_type));
185 return false;
186 }
187 }
188 return true;
189}
Austin Schuh43c6a352019-09-30 22:22:10 -0700190
Brian Silvermancf4fb662021-02-10 17:54:53 -0800191// Writes an array of FieldElement (with the definition in "type") to the
192// builder. Returns the offset of the resulting table.
James Kuszmaul768c4682023-10-12 21:07:16 -0700193std::optional<Element> WriteObject(FlatbufferType type,
194 const ::std::vector<FieldElement> &elements,
195 flatbuffers::FlatBufferBuilder *fbb) {
196 // End of a nested object! Add it.
197 if (type.IsTable()) {
198 const flatbuffers::uoffset_t start = fbb->StartTable();
Austin Schuh43c6a352019-09-30 22:22:10 -0700199
James Kuszmaul768c4682023-10-12 21:07:16 -0700200 ::std::vector<bool> fields_in_use(type.NumberFields(), false);
Austin Schuh43c6a352019-09-30 22:22:10 -0700201
James Kuszmaul768c4682023-10-12 21:07:16 -0700202 for (const FieldElement &field_element : elements) {
203 AddSingleElement(type, field_element, &fields_in_use, fbb);
204 }
205
206 return Element{
207 flatbuffers::Offset<flatbuffers::String>{fbb->EndTable(start)}};
208 } else if (type.IsStruct()) {
209 // In order to write an inline struct, we need to fill out each field at the
210 // correct position inline in memory. In order to do this, we retrieve the
211 // offset/size of each field, and directly populate that memory with the
212 // relevant value.
213 std::vector<uint8_t> buffer(type.InlineSize(), 0);
214 for (size_t field_index = 0;
215 field_index < static_cast<size_t>(type.NumberFields());
216 ++field_index) {
217 auto it = std::find_if(elements.begin(), elements.end(),
218 [field_index](const FieldElement &field) {
219 return field.field_index ==
220 static_cast<int>(field_index);
221 });
222 if (it == elements.end()) {
223 fprintf(stderr,
224 "All fields must be specified for struct types (field %s "
225 "missing).\n",
226 type.FieldName(field_index).data());
227 return std::nullopt;
228 }
229
230 uint8_t *field_data = buffer.data() + type.StructFieldOffset(field_index);
231 const size_t field_size = type.FieldInlineSize(field_index);
232 switch (it->element.type) {
233 case Element::ElementType::INT:
234 if (!SetStructElement(type, field_index, it->element.int_element,
235 field_data)) {
236 return std::nullopt;
237 }
238 break;
239 case Element::ElementType::DOUBLE:
240 if (!SetStructElement(type, field_index, it->element.double_element,
241 field_data)) {
242 return std::nullopt;
243 }
244 break;
245 case Element::ElementType::STRUCT:
246 CHECK_EQ(field_size, it->element.struct_data.size());
247 memcpy(field_data, it->element.struct_data.data(), field_size);
248 break;
249 case Element::ElementType::OFFSET:
250 LOG(FATAL)
251 << "This should be unreachable; structs cannot contain offsets.";
252 break;
253 }
254 }
255 return Element{buffer};
Austin Schuh43c6a352019-09-30 22:22:10 -0700256 }
James Kuszmaul768c4682023-10-12 21:07:16 -0700257 LOG(FATAL) << "Unimplemented.";
Austin Schuh43c6a352019-09-30 22:22:10 -0700258}
259
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700260// Class to parse JSON into a flatbuffer.
261//
262// The basic strategy is that we need to do everything backwards. So we need to
263// build up what we need to do fully in memory, then do it.
264//
265// The driver for this is that strings need to be fully created before the
266// tables that use them. Same for sub messages. But, we only know we have them
Austin Schuh43c6a352019-09-30 22:22:10 -0700267// all when the structure ends. So, store each sub message in a
268// FieldElement and put them in the table at the end when we finish up
269// each message. Same goes for vectors.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700270class JsonParser {
271 public:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800272 JsonParser(flatbuffers::FlatBufferBuilder *fbb) : fbb_(fbb) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700273 ~JsonParser() {}
274
275 // Parses the json into a flatbuffer. Returns either an empty vector on
276 // error, or a vector with the flatbuffer data in it.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800277 flatbuffers::Offset<flatbuffers::Table> Parse(const std::string_view data,
278 FlatbufferType type) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700279 flatbuffers::uoffset_t end = 0;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800280 bool result = DoParse(type, data, &end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700281
282 if (result) {
283 // On success, finish the table and build the vector.
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800284 return flatbuffers::Offset<flatbuffers::Table>(end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700285 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800286 return flatbuffers::Offset<flatbuffers::Table>(0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700287 }
288 }
289
290 private:
291 // Setters and getters for in_vector (at the current level of the stack)
292 bool in_vector() const { return stack_.back().in_vector; }
293 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
294
295 // Parses the flatbuffer. This is a second method so we can do easier
296 // cleanup at the top level. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800297 bool DoParse(FlatbufferType type, const std::string_view data,
298 flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700299
300 // Adds *_value for the provided field. If we are in a vector, queues the
Alex Perrycb7da4b2019-08-28 19:35:56 -0700301 // data up in vector_elements. Returns true on success.
James Kuszmaul768c4682023-10-12 21:07:16 -0700302 bool AddElement(int field_index, absl::int128 int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700303 bool AddElement(int field_index, double double_value);
304 bool AddElement(int field_index, const ::std::string &data);
305
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700306 // Finishes a vector for the provided field index. Returns true on success.
307 bool FinishVector(int field_index);
308
309 // Pushes an element as part of a vector. Returns true on success.
310 bool PushElement(flatbuffers::ElementaryType elementary_type,
James Kuszmaul768c4682023-10-12 21:07:16 -0700311 absl::int128 int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700312 bool PushElement(flatbuffers::ElementaryType elementary_type,
313 double double_value);
314 bool PushElement(flatbuffers::ElementaryType elementary_type,
315 flatbuffers::Offset<flatbuffers::String> offset_value);
James Kuszmaul768c4682023-10-12 21:07:16 -0700316 bool PushElement(const FlatbufferType &type,
317 const std::vector<uint8_t> &struct_data);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800318 flatbuffers::FlatBufferBuilder *fbb_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700319
320 // This holds the state information that is needed as you recurse into
321 // nested structures.
322 struct FlatBufferContext {
323 // Type of the current type.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800324 FlatbufferType type;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700325 // If true, we are parsing a vector.
326 bool in_vector;
327 // The field index of the current field.
328 int field_index;
329 // Name of the current field.
330 ::std::string field_name;
331
332 // Field elements that need to be inserted.
333 ::std::vector<FieldElement> elements;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700334
335 // For scalar types (not strings, and not nested tables), the vector ends
336 // up being implemented as a start and end, and a block of data. So we
337 // can't just push offsets in as we go. We either need to reproduce the
James Kuszmaul768c4682023-10-12 21:07:16 -0700338 // logic inside flatbuffers, or build up vectors of the data. Vectors
339 // will be a bit of extra stack space, but whatever.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700340 //
341 // Strings and nested structures are vectors of offsets.
342 // into the vector. Once you get to the end, you build up a vector and
343 // push that into the field.
344 ::std::vector<Element> vector_elements;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700345 };
346 ::std::vector<FlatBufferContext> stack_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700347};
348
Brian Silvermancf4fb662021-02-10 17:54:53 -0800349bool JsonParser::DoParse(FlatbufferType type, const std::string_view data,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700350 flatbuffers::uoffset_t *table_end) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800351 ::std::vector<FlatbufferType> stack;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700352
353 Tokenizer t(data);
354
355 // Main loop. Run until we get an end.
356 while (true) {
357 Tokenizer::TokenType token = t.Next();
358
359 switch (token) {
360 case Tokenizer::TokenType::kEnd:
361 if (stack_.size() != 0) {
Austin Schuh217a9782019-12-21 23:02:50 -0800362 fprintf(stderr, "Failed to unwind stack all the way\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700363 return false;
364 } else {
365 return true;
366 }
367 break;
368 case Tokenizer::TokenType::kError:
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800369 fprintf(stderr, "Encountered an error in the tokenizer\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700370 return false;
371 break;
372
373 case Tokenizer::TokenType::kStartObject: // {
374 if (stack_.size() == 0) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800375 stack_.push_back({type, false, -1, "", {}, {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700376 } else {
377 int field_index = stack_.back().field_index;
378
Brian Silvermancf4fb662021-02-10 17:54:53 -0800379 if (!stack_.back().type.FieldIsSequence(field_index)) {
Austin Schuh217a9782019-12-21 23:02:50 -0800380 fprintf(stderr, "Field '%s' is not a sequence\n",
381 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700382 return false;
383 }
384
James Kuszmaulbb60dfd2023-01-05 17:13:11 -0800385 if (in_vector() != stack_.back().type.FieldIsRepeating(field_index)) {
386 fprintf(stderr,
387 "Field '%s' is%s supposed to be a vector, but is a %s.\n",
388 stack_.back().field_name.c_str(), in_vector() ? " not" : "",
389 in_vector() ? "vector" : "bare object");
390 return false;
391 }
392
Brian Silvermancf4fb662021-02-10 17:54:53 -0800393 stack_.push_back({stack_.back().type.FieldType(field_index),
394 false,
395 -1,
396 "",
397 {},
398 {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700399 }
400 break;
401 case Tokenizer::TokenType::kEndObject: // }
402 if (stack_.size() == 0) {
403 // Somehow we popped more than we pushed. Error.
Austin Schuh217a9782019-12-21 23:02:50 -0800404 fprintf(stderr, "Empty stack\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700405 return false;
406 } else {
James Kuszmaul768c4682023-10-12 21:07:16 -0700407 // End of a nested object! Add it.
408 std::optional<Element> object =
409 WriteObject(stack_.back().type, stack_.back().elements, fbb_);
410 if (!object.has_value()) {
411 return false;
412 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700413
414 // We now want to talk about the parent structure. Pop the child.
415 stack_.pop_back();
416
417 if (stack_.size() == 0) {
James Kuszmaul768c4682023-10-12 21:07:16 -0700418 CHECK_EQ(static_cast<int>(object->type),
419 static_cast<int>(Element::ElementType::OFFSET))
420 << ": JSON parsing only supports parsing flatbuffer tables.";
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700421 // Instead of queueing it up in the stack, return it through the
422 // passed in variable.
James Kuszmaul768c4682023-10-12 21:07:16 -0700423 *table_end = object->offset_element.o;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700424 } else {
425 // And now we can add it.
426 const int field_index = stack_.back().field_index;
427
428 // Do the right thing if we are in a vector.
429 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700430 stack_.back().vector_elements.emplace_back(
James Kuszmaul768c4682023-10-12 21:07:16 -0700431 std::move(object.value()));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700432 } else {
James Kuszmaul768c4682023-10-12 21:07:16 -0700433 stack_.back().elements.emplace_back(field_index,
434 std::move(object.value()));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700435 }
436 }
437 }
438 break;
439
440 case Tokenizer::TokenType::kStartArray: // [
441 if (stack_.size() == 0) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800442 fprintf(stderr,
443 "We don't support an array of structs at the root level.\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700444 return false;
445 }
446 // Sanity check that we aren't trying to make a vector of vectors.
447 if (in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800448 fprintf(stderr, "We don't support vectors of vectors.\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700449 return false;
450 }
451 set_in_vector(true);
452
453 break;
454 case Tokenizer::TokenType::kEndArray: { // ]
455 if (!in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800456 fprintf(stderr, "Encountered ']' with no prior '['.\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700457 return false;
458 }
459
460 const int field_index = stack_.back().field_index;
461
462 if (!FinishVector(field_index)) return false;
463
464 set_in_vector(false);
465 } break;
466
467 case Tokenizer::TokenType::kTrueValue: // true
468 case Tokenizer::TokenType::kFalseValue: // false
469 case Tokenizer::TokenType::kNumberValue: {
470 bool is_int = true;
471 double double_value;
James Kuszmaul768c4682023-10-12 21:07:16 -0700472 absl::int128 int_value;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700473 if (token == Tokenizer::TokenType::kTrueValue) {
474 int_value = 1;
475 } else if (token == Tokenizer::TokenType::kFalseValue) {
476 int_value = 0;
477 } else if (!t.FieldAsInt(&int_value)) {
478 if (t.FieldAsDouble(&double_value)) {
479 is_int = false;
480 } else {
481 fprintf(stderr, "Got a invalid number '%s'\n",
482 t.field_value().c_str());
483 return false;
484 }
485 }
486
487 const int field_index = stack_.back().field_index;
488
489 if (is_int) {
490 // No need to get too stressed about bool vs int. Convert them all.
James Kuszmaul768c4682023-10-12 21:07:16 -0700491 absl::int128 val = int_value;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700492 if (!AddElement(field_index, val)) return false;
493 } else {
494 if (!AddElement(field_index, double_value)) return false;
495 }
496 } break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700497 case Tokenizer::TokenType::kStringValue: // string value
498 {
499 const int field_index = stack_.back().field_index;
500
501 if (!AddElement(field_index, t.field_value())) return false;
502 } break;
503 case Tokenizer::TokenType::kField: // field name
504 {
505 stack_.back().field_name = t.field_name();
Brian Silvermancf4fb662021-02-10 17:54:53 -0800506 stack_.back().field_index =
507 stack_.back().type.FieldIndex(stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700508
509 if (stack_.back().field_index == -1) {
Austin Schuh217a9782019-12-21 23:02:50 -0800510 fprintf(stderr, "Invalid field name '%s'\n",
511 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700512 return false;
513 }
514 } break;
515 }
516 }
517 return false;
518}
519
James Kuszmaul768c4682023-10-12 21:07:16 -0700520bool JsonParser::AddElement(int field_index, absl::int128 int_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800521 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800522 fprintf(stderr,
523 "Type and json disagree on if we are in a vector or not (JSON "
524 "believes that we are%s in a vector for field '%s').\n",
525 in_vector() ? "" : " not",
526 stack_.back().type.FieldName(field_index).data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700527 return false;
528 }
529
530 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700531 stack_.back().vector_elements.emplace_back(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700532 } else {
533 stack_.back().elements.emplace_back(field_index, int_value);
534 }
535 return true;
536}
537
538bool JsonParser::AddElement(int field_index, double double_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800539 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800540 fprintf(stderr,
541 "Type and json disagree on if we are in a vector or not (JSON "
542 "believes that we are%s in a vector for field '%s').\n",
543 in_vector() ? "" : " not",
544 stack_.back().type.FieldName(field_index).data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700545 return false;
546 }
547
548 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700549 stack_.back().vector_elements.emplace_back(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700550 } else {
551 stack_.back().elements.emplace_back(field_index, double_value);
552 }
553 return true;
554}
555
556bool JsonParser::AddElement(int field_index, const ::std::string &data) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800557 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800558 fprintf(stderr,
559 "Type and json disagree on if we are in a vector or not (JSON "
560 "believes that we are%s in a vector for field '%s').\n",
561 in_vector() ? "" : " not",
562 stack_.back().type.FieldName(field_index).data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700563 return false;
564 }
565
Alex Perrycb7da4b2019-08-28 19:35:56 -0700566 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800567 stack_.back().type.FieldElementaryType(field_index);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700568 switch (elementary_type) {
569 case flatbuffers::ET_CHAR:
570 case flatbuffers::ET_UCHAR:
571 case flatbuffers::ET_SHORT:
572 case flatbuffers::ET_USHORT:
573 case flatbuffers::ET_INT:
574 case flatbuffers::ET_UINT:
575 case flatbuffers::ET_LONG:
576 case flatbuffers::ET_ULONG:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800577 if (stack_.back().type.FieldIsEnum(field_index)) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700578 // We have an enum.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800579 const FlatbufferType type = stack_.back().type;
580 const FlatbufferType enum_type = type.FieldType(field_index);
581 CHECK(enum_type.IsEnum());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700582
James Kuszmaul768c4682023-10-12 21:07:16 -0700583 const std::optional<absl::int128> int_value = enum_type.EnumValue(data);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700584
Brian Silvermancf4fb662021-02-10 17:54:53 -0800585 if (!int_value) {
586 const std::string_view name = type.FieldName(field_index);
587 fprintf(stderr, "Enum value '%s' not found for field '%.*s'\n",
588 data.c_str(), static_cast<int>(name.size()), name.data());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700589 return false;
590 }
591
592 if (in_vector()) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800593 stack_.back().vector_elements.emplace_back(*int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700594 } else {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800595 stack_.back().elements.emplace_back(field_index, *int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700596 }
597 return true;
598 }
599 case flatbuffers::ET_UTYPE:
600 case flatbuffers::ET_BOOL:
601 case flatbuffers::ET_FLOAT:
602 case flatbuffers::ET_DOUBLE:
603 case flatbuffers::ET_STRING:
604 case flatbuffers::ET_SEQUENCE:
605 break;
606 }
607
608 if (in_vector()) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800609 stack_.back().vector_elements.emplace_back(fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700610 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800611 stack_.back().elements.emplace_back(field_index, fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700612 }
613 return true;
614}
615
Brian Silvermancf4fb662021-02-10 17:54:53 -0800616bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -0700617 ::std::vector<bool> *fields_in_use,
618 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700619 if ((*fields_in_use)[field_element.field_index]) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800620 const std::string_view name = type.FieldName(field_element.field_index);
621 fprintf(stderr, "Duplicate field: '%.*s'\n", static_cast<int>(name.size()),
622 name.data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700623 return false;
624 }
625
626 (*fields_in_use)[field_element.field_index] = true;
627
628 switch (field_element.element.type) {
629 case Element::ElementType::INT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800630 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700631 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700632 case Element::ElementType::DOUBLE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800633 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700634 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700635 case Element::ElementType::OFFSET:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800636 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700637 field_element.element.offset_element, fbb);
James Kuszmaul768c4682023-10-12 21:07:16 -0700638 case Element::ElementType::STRUCT:
639 return AddSingleElement(type, field_element.field_index,
640 field_element.element.struct_data, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700641 }
642 return false;
643}
644
James Kuszmaul768c4682023-10-12 21:07:16 -0700645bool AddSingleElement(FlatbufferType type, int field_index,
646 absl::int128 int_value,
Brian Silvermancf4fb662021-02-10 17:54:53 -0800647 flatbuffers::FlatBufferBuilder *fbb
Austin Schuh43c6a352019-09-30 22:22:10 -0700648
649) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700650 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
651 static_cast<flatbuffers::voffset_t>(field_index));
652
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700653 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800654 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700655 switch (elementary_type) {
656 case flatbuffers::ET_BOOL:
James Kuszmaul768c4682023-10-12 21:07:16 -0700657 fbb->AddElement<bool>(field_offset, static_cast<bool>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700658 return true;
659 case flatbuffers::ET_CHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700660 fbb->AddElement<int8_t>(field_offset, static_cast<int8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700661 return true;
662 case flatbuffers::ET_UCHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700663 fbb->AddElement<uint8_t>(field_offset, static_cast<uint8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700664 return true;
665 case flatbuffers::ET_SHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700666 fbb->AddElement<int16_t>(field_offset, static_cast<int16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700667 return true;
668 case flatbuffers::ET_USHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700669 fbb->AddElement<uint16_t>(field_offset, static_cast<uint16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700670 return true;
671 case flatbuffers::ET_INT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700672 fbb->AddElement<int32_t>(field_offset, static_cast<int32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700673 return true;
674 case flatbuffers::ET_UINT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700675 fbb->AddElement<uint32_t>(field_offset, static_cast<uint32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700676 return true;
677 case flatbuffers::ET_LONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700678 fbb->AddElement<int64_t>(field_offset, static_cast<int64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700679 return true;
680 case flatbuffers::ET_ULONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700681 fbb->AddElement<uint64_t>(field_offset, static_cast<uint64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700682 return true;
James Kuszmaul768c4682023-10-12 21:07:16 -0700683 // The floating point cases occur when someone specifies an integer in the
684 // JSON for a double field.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700685 case flatbuffers::ET_FLOAT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700686 fbb->AddElement<float>(field_offset, static_cast<float>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700687 return true;
688 case flatbuffers::ET_DOUBLE:
James Kuszmaul768c4682023-10-12 21:07:16 -0700689 fbb->AddElement<double>(field_offset, static_cast<double>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700690 return true;
691 case flatbuffers::ET_STRING:
692 case flatbuffers::ET_UTYPE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800693 case flatbuffers::ET_SEQUENCE: {
694 const std::string_view name = type.FieldName(field_index);
695 fprintf(stderr,
696 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
697 static_cast<int>(name.size()), name.data(),
698 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700699 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800700 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700701 };
702 return false;
703}
704
Brian Silvermancf4fb662021-02-10 17:54:53 -0800705bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
Austin Schuh43c6a352019-09-30 22:22:10 -0700706 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700707 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
708 static_cast<flatbuffers::voffset_t>(field_index));
709
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700710 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800711 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700712 switch (elementary_type) {
713 case flatbuffers::ET_UTYPE:
714 case flatbuffers::ET_BOOL:
715 case flatbuffers::ET_CHAR:
716 case flatbuffers::ET_UCHAR:
717 case flatbuffers::ET_SHORT:
718 case flatbuffers::ET_USHORT:
719 case flatbuffers::ET_INT:
720 case flatbuffers::ET_UINT:
721 case flatbuffers::ET_LONG:
722 case flatbuffers::ET_ULONG:
723 case flatbuffers::ET_STRING:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800724 case flatbuffers::ET_SEQUENCE: {
725 const std::string_view name = type.FieldName(field_index);
726 fprintf(stderr,
727 "Mismatched type for field '%.*s'. Got: double, expected %s\n",
728 static_cast<int>(name.size()), name.data(),
729 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700730 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800731 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700732 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800733 fbb->AddElement<float>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700734 return true;
735 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800736 fbb->AddElement<double>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700737 return true;
738 }
739 return false;
740}
James Kuszmaul768c4682023-10-12 21:07:16 -0700741
Brian Silvermancf4fb662021-02-10 17:54:53 -0800742bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700743 flatbuffers::Offset<flatbuffers::String> offset_element,
744 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700745 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
746 static_cast<flatbuffers::voffset_t>(field_index));
747
748 // Vectors will always be Offset<>'s.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800749 if (type.FieldIsRepeating(field_index)) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700750 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700751 return true;
752 }
753
754 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800755 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700756 switch (elementary_type) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700757 case flatbuffers::ET_CHAR:
758 case flatbuffers::ET_UCHAR:
759 case flatbuffers::ET_SHORT:
760 case flatbuffers::ET_USHORT:
761 case flatbuffers::ET_INT:
762 case flatbuffers::ET_UINT:
763 case flatbuffers::ET_LONG:
764 case flatbuffers::ET_ULONG:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700765 case flatbuffers::ET_UTYPE:
766 case flatbuffers::ET_BOOL:
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700767 case flatbuffers::ET_FLOAT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800768 case flatbuffers::ET_DOUBLE: {
769 const std::string_view name = type.FieldName(field_index);
770 fprintf(stderr,
771 "Mismatched type for field '%.*s'. Got: string, expected %s\n",
772 static_cast<int>(name.size()), name.data(),
773 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700774 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800775 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700776 case flatbuffers::ET_STRING:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700777 case flatbuffers::ET_SEQUENCE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700778 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700779 return true;
780 }
781 return false;
782}
783
James Kuszmaul768c4682023-10-12 21:07:16 -0700784bool AddSingleElement(FlatbufferType type, int field_index,
785 const std::vector<uint8_t> &data,
786 flatbuffers::FlatBufferBuilder *fbb) {
787 // Structs are always inline.
788 // We have to do somewhat manual serialization to get the struct into place,
789 // since the regular FlatBufferBuilder assumes that you will know the type of
790 // the struct that you are constructing at compile time.
791 fbb->Align(type.FieldType(field_index).Alignment());
792 fbb->PushBytes(data.data(), data.size());
793 fbb->AddStructOffset(flatbuffers::FieldIndexToOffset(
794 static_cast<flatbuffers::voffset_t>(field_index)),
795 fbb->GetSize());
796 return true;
797}
798
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700799bool JsonParser::FinishVector(int field_index) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800800 // Vectors have a start (unfortunately which needs to know the size)
James Kuszmaul65541cb2022-11-08 14:53:47 -0800801 const size_t inline_size = stack_.back().type.FieldInlineSize(field_index);
James Kuszmaul768c4682023-10-12 21:07:16 -0700802 const size_t alignment = stack_.back().type.FieldInlineAlignment(field_index);
James Kuszmaul65541cb2022-11-08 14:53:47 -0800803 fbb_->StartVector(stack_.back().vector_elements.size(), inline_size,
James Kuszmaul768c4682023-10-12 21:07:16 -0700804 /*align=*/alignment);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700805
806 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800807 stack_.back().type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700808
809 // Then the data (in reverse order for some reason...)
Alex Perrycb7da4b2019-08-28 19:35:56 -0700810 for (size_t i = stack_.back().vector_elements.size(); i > 0;) {
811 const Element &element = stack_.back().vector_elements[--i];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700812 switch (element.type) {
813 case Element::ElementType::INT:
814 if (!PushElement(elementary_type, element.int_element)) return false;
815 break;
816 case Element::ElementType::DOUBLE:
817 if (!PushElement(elementary_type, element.double_element)) return false;
818 break;
819 case Element::ElementType::OFFSET:
820 if (!PushElement(elementary_type, element.offset_element)) return false;
821 break;
James Kuszmaul768c4682023-10-12 21:07:16 -0700822 case Element::ElementType::STRUCT:
823 if (!PushElement(stack_.back().type.FieldType(field_index),
824 element.struct_data))
825 return false;
826 break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700827 }
828 }
829
830 // Then an End which is placed into the buffer the same as any other offset.
831 stack_.back().elements.emplace_back(
832 field_index, flatbuffers::Offset<flatbuffers::String>(
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800833 fbb_->EndVector(stack_.back().vector_elements.size())));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700834 stack_.back().vector_elements.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700835 return true;
836}
837
838bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
James Kuszmaul768c4682023-10-12 21:07:16 -0700839 absl::int128 int_value) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700840 switch (elementary_type) {
841 case flatbuffers::ET_BOOL:
James Kuszmaul768c4682023-10-12 21:07:16 -0700842 fbb_->PushElement<bool>(static_cast<bool>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700843 return true;
844 case flatbuffers::ET_CHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700845 fbb_->PushElement<int8_t>(static_cast<int8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700846 return true;
847 case flatbuffers::ET_UCHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700848 fbb_->PushElement<uint8_t>(static_cast<uint8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700849 return true;
850 case flatbuffers::ET_SHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700851 fbb_->PushElement<int16_t>(static_cast<int16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700852 return true;
853 case flatbuffers::ET_USHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700854 fbb_->PushElement<uint16_t>(static_cast<uint16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700855 return true;
856 case flatbuffers::ET_INT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700857 fbb_->PushElement<int32_t>(static_cast<int32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700858 return true;
859 case flatbuffers::ET_UINT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700860 fbb_->PushElement<uint32_t>(static_cast<uint32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700861 return true;
862 case flatbuffers::ET_LONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700863 fbb_->PushElement<int64_t>(static_cast<int64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700864 return true;
865 case flatbuffers::ET_ULONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700866 fbb_->PushElement<uint64_t>(static_cast<uint64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700867 return true;
868 case flatbuffers::ET_FLOAT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700869 fbb_->PushElement<float>(static_cast<float>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700870 return true;
871 case flatbuffers::ET_DOUBLE:
James Kuszmaul768c4682023-10-12 21:07:16 -0700872 fbb_->PushElement<double>(static_cast<double>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700873 return true;
874 case flatbuffers::ET_STRING:
875 case flatbuffers::ET_UTYPE:
876 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800877 fprintf(stderr,
878 "Mismatched type for field '%s'. Got: integer, expected %s\n",
879 stack_.back().field_name.c_str(),
880 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700881 return false;
882 };
883 return false;
884}
885
886bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
887 double double_value) {
888 switch (elementary_type) {
889 case flatbuffers::ET_UTYPE:
890 case flatbuffers::ET_BOOL:
891 case flatbuffers::ET_CHAR:
892 case flatbuffers::ET_UCHAR:
893 case flatbuffers::ET_SHORT:
894 case flatbuffers::ET_USHORT:
895 case flatbuffers::ET_INT:
896 case flatbuffers::ET_UINT:
897 case flatbuffers::ET_LONG:
898 case flatbuffers::ET_ULONG:
899 case flatbuffers::ET_STRING:
900 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800901 fprintf(stderr,
902 "Mismatched type for field '%s'. Got: double, expected %s\n",
903 stack_.back().field_name.c_str(),
904 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700905 return false;
906 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800907 fbb_->PushElement<float>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700908 return true;
909 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800910 fbb_->PushElement<double>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700911 return true;
912 }
913 return false;
914}
915
James Kuszmaul768c4682023-10-12 21:07:16 -0700916bool JsonParser::PushElement(const FlatbufferType &type,
917 const std::vector<uint8_t> &struct_data) {
918 // To add a struct to a vector, we just need to get the relevant bytes pushed
919 // straight into the builder. The FlatBufferBuilder normally expects that you
920 // will know the type of your struct at compile-time, so doesn't have a
921 // first-class way to do this.
922 fbb_->Align(type.Alignment());
923 fbb_->PushBytes(struct_data.data(), struct_data.size());
924 return true;
925}
926
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700927bool JsonParser::PushElement(
928 flatbuffers::ElementaryType elementary_type,
929 flatbuffers::Offset<flatbuffers::String> offset_value) {
930 switch (elementary_type) {
931 case flatbuffers::ET_UTYPE:
932 case flatbuffers::ET_BOOL:
933 case flatbuffers::ET_CHAR:
934 case flatbuffers::ET_UCHAR:
935 case flatbuffers::ET_SHORT:
936 case flatbuffers::ET_USHORT:
937 case flatbuffers::ET_INT:
938 case flatbuffers::ET_UINT:
939 case flatbuffers::ET_LONG:
940 case flatbuffers::ET_ULONG:
941 case flatbuffers::ET_FLOAT:
942 case flatbuffers::ET_DOUBLE:
Austin Schuh217a9782019-12-21 23:02:50 -0800943 fprintf(stderr,
944 "Mismatched type for field '%s'. Got: sequence, expected %s\n",
945 stack_.back().field_name.c_str(),
946 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700947 return false;
948 case flatbuffers::ET_STRING:
949 case flatbuffers::ET_SEQUENCE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800950 fbb_->PushElement(offset_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700951 return true;
952 }
953 return false;
954}
955
956} // namespace
957
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800958flatbuffers::Offset<flatbuffers::Table> JsonToFlatbuffer(
Brian Silvermancf4fb662021-02-10 17:54:53 -0800959 const std::string_view data, FlatbufferType type,
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800960 flatbuffers::FlatBufferBuilder *fbb) {
961 JsonParser p(fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800962 return p.Parse(data, type);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800963}
964
Brian Silvermancf4fb662021-02-10 17:54:53 -0800965flatbuffers::DetachedBuffer JsonToFlatbuffer(const std::string_view data,
966 FlatbufferType type) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800967 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -0800968 fbb.ForceDefaults(true);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800969
970 const flatbuffers::Offset<flatbuffers::Table> result =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800971 JsonToFlatbuffer(data, type, &fbb);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800972 if (result.o != 0) {
973 fbb.Finish(result);
974
975 return fbb.Release();
976 } else {
977 // Otherwise return an empty vector.
978 return flatbuffers::DetachedBuffer();
979 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700980}
981
Austin Schuhd3936202020-04-07 20:11:07 -0700982namespace {
983
984// A visitor which manages skipping the contents of vectors that are longer than
985// a specified threshold.
986class TruncatingStringVisitor : public flatbuffers::IterationVisitor {
987 public:
988 TruncatingStringVisitor(size_t max_vector_size, std::string delimiter,
989 bool quotes, std::string indent, bool vdelimited)
990 : max_vector_size_(max_vector_size),
991 to_string_(delimiter, quotes, indent, vdelimited) {}
992 ~TruncatingStringVisitor() override {}
993
994 void StartSequence() override {
995 if (should_skip()) return;
996 to_string_.StartSequence();
997 }
998 void EndSequence() override {
999 if (should_skip()) return;
1000 to_string_.EndSequence();
1001 }
1002 void Field(size_t field_idx, size_t set_idx, flatbuffers::ElementaryType type,
Austin Schuh7c75e582020-11-14 16:41:18 -08001003 bool is_repeating, const flatbuffers::TypeTable *type_table,
Austin Schuhd3936202020-04-07 20:11:07 -07001004 const char *name, const uint8_t *val) override {
1005 if (should_skip()) return;
Austin Schuh7c75e582020-11-14 16:41:18 -08001006 to_string_.Field(field_idx, set_idx, type, is_repeating, type_table, name,
Austin Schuhd3936202020-04-07 20:11:07 -07001007 val);
1008 }
1009 void UType(uint8_t value, const char *name) override {
1010 if (should_skip()) return;
1011 to_string_.UType(value, name);
1012 }
1013 void Bool(bool value) override {
1014 if (should_skip()) return;
1015 to_string_.Bool(value);
1016 }
1017 void Char(int8_t value, const char *name) override {
1018 if (should_skip()) return;
1019 to_string_.Char(value, name);
1020 }
1021 void UChar(uint8_t value, const char *name) override {
1022 if (should_skip()) return;
1023 to_string_.UChar(value, name);
1024 }
1025 void Short(int16_t value, const char *name) override {
1026 if (should_skip()) return;
1027 to_string_.Short(value, name);
1028 }
1029 void UShort(uint16_t value, const char *name) override {
1030 if (should_skip()) return;
1031 to_string_.UShort(value, name);
1032 }
1033 void Int(int32_t value, const char *name) override {
1034 if (should_skip()) return;
1035 to_string_.Int(value, name);
1036 }
1037 void UInt(uint32_t value, const char *name) override {
1038 if (should_skip()) return;
1039 to_string_.UInt(value, name);
1040 }
1041 void Long(int64_t value) override {
1042 if (should_skip()) return;
1043 to_string_.Long(value);
1044 }
1045 void ULong(uint64_t value) override {
1046 if (should_skip()) return;
1047 to_string_.ULong(value);
1048 }
1049 void Float(float value) override {
1050 if (should_skip()) return;
1051 to_string_.Float(value);
1052 }
1053 void Double(double value) override {
1054 if (should_skip()) return;
1055 to_string_.Double(value);
1056 }
1057 void String(const flatbuffers::String *value) override {
1058 if (should_skip()) return;
1059 to_string_.String(value);
1060 }
1061 void Unknown(const uint8_t *value) override {
1062 if (should_skip()) return;
1063 to_string_.Unknown(value);
1064 }
1065 void Element(size_t i, flatbuffers::ElementaryType type,
1066 const flatbuffers::TypeTable *type_table,
1067 const uint8_t *val) override {
1068 if (should_skip()) return;
1069 to_string_.Element(i, type, type_table, val);
1070 }
1071
1072 virtual void StartVector(size_t size) override {
1073 if (should_skip()) {
1074 ++skip_levels_;
1075 return;
1076 }
1077 if (size > max_vector_size_) {
1078 ++skip_levels_;
Austin Schuh041fe9f2021-10-16 23:01:15 -07001079 to_string_.s += "[ \"... " + std::to_string(size) + " elements ...\" ]";
Austin Schuhd3936202020-04-07 20:11:07 -07001080 return;
1081 }
1082 to_string_.StartVector(size);
1083 }
1084 virtual void EndVector() override {
1085 if (should_skip()) {
1086 --skip_levels_;
1087 return;
1088 }
1089 to_string_.EndVector();
1090 }
1091
1092 std::string &string() { return to_string_.s; }
1093
1094 private:
1095 bool should_skip() const { return skip_levels_ > 0; }
1096
1097 const size_t max_vector_size_;
1098 flatbuffers::ToStringVisitor to_string_;
1099 int skip_levels_ = 0;
1100};
1101
1102} // namespace
1103
Austin Schuhe93d8642019-10-13 15:27:07 -07001104::std::string TableFlatbufferToJson(const flatbuffers::Table *t,
1105 const ::flatbuffers::TypeTable *typetable,
Ravago Jonescf453ab2020-05-06 21:14:53 -07001106 JsonOptions json_options) {
Austin Schuhe93d8642019-10-13 15:27:07 -07001107 // It is pretty common to get passed in a nullptr when a test fails. Rather
1108 // than CHECK, return a more user friendly result.
1109 if (t == nullptr) {
1110 return "null";
1111 }
Ravago Jonescf453ab2020-05-06 21:14:53 -07001112 TruncatingStringVisitor tostring_visitor(
1113 json_options.max_vector_size, json_options.multi_line ? "\n" : " ", true,
1114 json_options.multi_line ? " " : "", json_options.multi_line);
Austin Schuhe93d8642019-10-13 15:27:07 -07001115 flatbuffers::IterateObject(reinterpret_cast<const uint8_t *>(t), typetable,
1116 &tostring_visitor);
Austin Schuhd3936202020-04-07 20:11:07 -07001117 return tostring_visitor.string();
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001118}
1119
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001120} // namespace aos