blob: 3f049d77ac9f4fc0d2917a3d71a7df3256bf48ae [file] [log] [blame]
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001#include "aos/json_to_flatbuffer.h"
2
3#include <cstddef>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cstdio>
James Kuszmaul3ae42262019-11-08 12:33:41 -08005#include <string_view>
6
Austin Schuh3e95e5d2019-09-20 00:08:54 -07007#include "flatbuffers/flatbuffers.h"
8#include "flatbuffers/minireflect.h"
Austin Schuhe93d8642019-10-13 15:27:07 -07009#include "glog/logging.h"
Austin Schuh3e95e5d2019-09-20 00:08:54 -070010
Philipp Schrader790cb542023-07-05 21:06:52 -070011#include "aos/flatbuffer_utils.h"
12#include "aos/json_tokenizer.h"
13
Austin Schuh3e95e5d2019-09-20 00:08:54 -070014// TODO(austin): Can we just do an Offset<void> ? It doesn't matter, so maybe
15// just say that.
16//
17// TODO(austin): I've yet to see how to create an ET_UTYPE, so I don't know what
18// one is and how to test it. So everything rejects it.
19
20namespace aos {
Austin Schuh3e95e5d2019-09-20 00:08:54 -070021namespace {
22
23// Class to hold one of the 3 json types for an array.
24struct Element {
25 // The type.
James Kuszmaul768c4682023-10-12 21:07:16 -070026 enum class ElementType { INT, DOUBLE, OFFSET, STRUCT };
Austin Schuh3e95e5d2019-09-20 00:08:54 -070027
28 // Constructs an Element holding an integer.
James Kuszmaul768c4682023-10-12 21:07:16 -070029 Element(absl::int128 new_int_element)
Austin Schuh3e95e5d2019-09-20 00:08:54 -070030 : int_element(new_int_element), type(ElementType::INT) {}
31 // Constructs an Element holding an double.
32 Element(double new_double_element)
33 : double_element(new_double_element), type(ElementType::DOUBLE) {}
34 // Constructs an Element holding an Offset.
35 Element(flatbuffers::Offset<flatbuffers::String> new_offset_element)
36 : offset_element(new_offset_element), type(ElementType::OFFSET) {}
James Kuszmaul768c4682023-10-12 21:07:16 -070037 // Constructs an Element holding a struct.
38 Element(std::vector<uint8_t> struct_data)
39 : /*initialize the union member to keep the compiler happy*/ int_element(
40 0),
41 struct_data(std::move(struct_data)),
42 type(ElementType::STRUCT) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -070043
44 // Union for the various datatypes.
45 union {
James Kuszmaul768c4682023-10-12 21:07:16 -070046 absl::int128 int_element;
Austin Schuh3e95e5d2019-09-20 00:08:54 -070047 double double_element;
48 flatbuffers::Offset<flatbuffers::String> offset_element;
49 };
James Kuszmaul768c4682023-10-12 21:07:16 -070050 // Because we can't know the maximum size of any potential structs at
51 // compile-time, we will use a vector to store the vector data inline.
52 // If you were to do a reinterpret_cast<StructType*>(struct_data.data()) then
53 // you would have an instance of the struct in question.
54 std::vector<uint8_t> struct_data;
Austin Schuh3e95e5d2019-09-20 00:08:54 -070055
56 // And an enum signaling which one is in use.
57 ElementType type;
58};
59
60// Structure to represent a field element.
61struct FieldElement {
James Kuszmaul768c4682023-10-12 21:07:16 -070062 FieldElement(int new_field_index, absl::int128 int_element)
Austin Schuh3e95e5d2019-09-20 00:08:54 -070063 : element(int_element), field_index(new_field_index) {}
64 FieldElement(int new_field_index, double double_element)
65 : element(double_element), field_index(new_field_index) {}
66 FieldElement(int new_field_index,
67 flatbuffers::Offset<flatbuffers::String> offset_element)
68 : element(offset_element), field_index(new_field_index) {}
James Kuszmaul768c4682023-10-12 21:07:16 -070069 FieldElement(int new_field_index, const Element &element)
70 : element(element), field_index(new_field_index) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -070071
72 // Data to write.
73 Element element;
74 // Field index. The type table which this index is for is stored outside this
75 // object.
76 int field_index;
77};
78
Austin Schuh43c6a352019-09-30 22:22:10 -070079// Adds a single element. This assumes that vectors have been dealt with
80// already. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -080081bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -070082 ::std::vector<bool> *fields_in_use,
83 flatbuffers::FlatBufferBuilder *fbb);
James Kuszmaul768c4682023-10-12 21:07:16 -070084bool AddSingleElement(FlatbufferType type, int field_index,
85 absl::int128 int_value,
Brian Silvermancf4fb662021-02-10 17:54:53 -080086 flatbuffers::FlatBufferBuilder *fbb);
87bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
88 flatbuffers::FlatBufferBuilder *fbb);
89bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -070090 flatbuffers::Offset<flatbuffers::String> offset_element,
91 flatbuffers::FlatBufferBuilder *fbb);
James Kuszmaul768c4682023-10-12 21:07:16 -070092bool AddSingleElement(FlatbufferType type, int field_index,
93 const std::vector<uint8_t> &struct_data,
94 flatbuffers::FlatBufferBuilder *fbb);
95
96template <typename T, typename U>
97void SetMemory(U value, uint8_t *destination) {
98 // destination may be poorly aligned. As such, we should not simply do
99 // *reinterpret_cast<T*>(destination) = value directly.
100 const T casted = static_cast<T>(value);
101 memcpy(destination, &casted, sizeof(T));
102}
103
104bool SetStructElement(FlatbufferType type, int field_index, absl::int128 value,
105 uint8_t *destination) {
106 const flatbuffers::ElementaryType elementary_type =
107 type.FieldElementaryType(field_index);
108 switch (elementary_type) {
109 case flatbuffers::ET_CHAR:
110 SetMemory<int8_t>(value, destination);
111 break;
112 case flatbuffers::ET_UCHAR:
113 SetMemory<uint8_t>(value, destination);
114 break;
115 case flatbuffers::ET_SHORT:
116 SetMemory<int16_t>(value, destination);
117 break;
118 case flatbuffers::ET_USHORT:
119 SetMemory<uint16_t>(value, destination);
120 break;
121 case flatbuffers::ET_INT:
122 SetMemory<int32_t>(value, destination);
123 break;
124 case flatbuffers::ET_UINT:
125 SetMemory<uint32_t>(value, destination);
126 break;
127 case flatbuffers::ET_LONG:
128 SetMemory<int64_t>(value, destination);
129 break;
130 case flatbuffers::ET_ULONG:
131 SetMemory<uint64_t>(value, destination);
132 break;
133 case flatbuffers::ET_BOOL:
134 SetMemory<bool>(value, destination);
135 break;
136 case flatbuffers::ET_FLOAT:
137 SetMemory<float>(value, destination);
138 break;
139 case flatbuffers::ET_DOUBLE:
140 SetMemory<double>(value, destination);
141 break;
142 case flatbuffers::ET_STRING:
143 case flatbuffers::ET_UTYPE:
144 case flatbuffers::ET_SEQUENCE: {
145 const std::string_view name = type.FieldName(field_index);
146 fprintf(stderr,
147 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
148 static_cast<int>(name.size()), name.data(),
149 ElementaryTypeName(elementary_type));
150 return false;
151 }
152 }
153 return true;
154}
155
156bool SetStructElement(FlatbufferType type, int field_index, double value,
157 uint8_t *destination) {
158 const flatbuffers::ElementaryType elementary_type =
159 type.FieldElementaryType(field_index);
160 switch (elementary_type) {
161 case flatbuffers::ET_FLOAT:
162 SetMemory<float>(value, destination);
163 break;
164 case flatbuffers::ET_DOUBLE:
165 SetMemory<double>(value, destination);
166 break;
167 case flatbuffers::ET_CHAR:
168 case flatbuffers::ET_UCHAR:
169 case flatbuffers::ET_SHORT:
170 case flatbuffers::ET_USHORT:
171 case flatbuffers::ET_INT:
172 case flatbuffers::ET_UINT:
173 case flatbuffers::ET_LONG:
174 case flatbuffers::ET_ULONG:
175 case flatbuffers::ET_BOOL:
176 case flatbuffers::ET_STRING:
177 case flatbuffers::ET_UTYPE:
178 case flatbuffers::ET_SEQUENCE: {
179 const std::string_view name = type.FieldName(field_index);
180 fprintf(stderr,
181 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
182 static_cast<int>(name.size()), name.data(),
183 ElementaryTypeName(elementary_type));
184 return false;
185 }
186 }
187 return true;
188}
Austin Schuh43c6a352019-09-30 22:22:10 -0700189
Brian Silvermancf4fb662021-02-10 17:54:53 -0800190// Writes an array of FieldElement (with the definition in "type") to the
191// builder. Returns the offset of the resulting table.
James Kuszmaul768c4682023-10-12 21:07:16 -0700192std::optional<Element> WriteObject(FlatbufferType type,
193 const ::std::vector<FieldElement> &elements,
194 flatbuffers::FlatBufferBuilder *fbb) {
195 // End of a nested object! Add it.
196 if (type.IsTable()) {
197 const flatbuffers::uoffset_t start = fbb->StartTable();
Austin Schuh43c6a352019-09-30 22:22:10 -0700198
James Kuszmaul768c4682023-10-12 21:07:16 -0700199 ::std::vector<bool> fields_in_use(type.NumberFields(), false);
Austin Schuh43c6a352019-09-30 22:22:10 -0700200
James Kuszmaul768c4682023-10-12 21:07:16 -0700201 for (const FieldElement &field_element : elements) {
202 AddSingleElement(type, field_element, &fields_in_use, fbb);
203 }
204
205 return Element{
206 flatbuffers::Offset<flatbuffers::String>{fbb->EndTable(start)}};
207 } else if (type.IsStruct()) {
208 // In order to write an inline struct, we need to fill out each field at the
209 // correct position inline in memory. In order to do this, we retrieve the
210 // offset/size of each field, and directly populate that memory with the
211 // relevant value.
212 std::vector<uint8_t> buffer(type.InlineSize(), 0);
213 for (size_t field_index = 0;
214 field_index < static_cast<size_t>(type.NumberFields());
215 ++field_index) {
216 auto it = std::find_if(elements.begin(), elements.end(),
217 [field_index](const FieldElement &field) {
218 return field.field_index ==
219 static_cast<int>(field_index);
220 });
221 if (it == elements.end()) {
222 fprintf(stderr,
223 "All fields must be specified for struct types (field %s "
224 "missing).\n",
225 type.FieldName(field_index).data());
226 return std::nullopt;
227 }
228
229 uint8_t *field_data = buffer.data() + type.StructFieldOffset(field_index);
230 const size_t field_size = type.FieldInlineSize(field_index);
231 switch (it->element.type) {
232 case Element::ElementType::INT:
233 if (!SetStructElement(type, field_index, it->element.int_element,
234 field_data)) {
235 return std::nullopt;
236 }
237 break;
238 case Element::ElementType::DOUBLE:
239 if (!SetStructElement(type, field_index, it->element.double_element,
240 field_data)) {
241 return std::nullopt;
242 }
243 break;
244 case Element::ElementType::STRUCT:
245 CHECK_EQ(field_size, it->element.struct_data.size());
246 memcpy(field_data, it->element.struct_data.data(), field_size);
247 break;
248 case Element::ElementType::OFFSET:
249 LOG(FATAL)
250 << "This should be unreachable; structs cannot contain offsets.";
251 break;
252 }
253 }
254 return Element{buffer};
Austin Schuh43c6a352019-09-30 22:22:10 -0700255 }
James Kuszmaul768c4682023-10-12 21:07:16 -0700256 LOG(FATAL) << "Unimplemented.";
Austin Schuh43c6a352019-09-30 22:22:10 -0700257}
258
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700259// Class to parse JSON into a flatbuffer.
260//
261// The basic strategy is that we need to do everything backwards. So we need to
262// build up what we need to do fully in memory, then do it.
263//
264// The driver for this is that strings need to be fully created before the
265// tables that use them. Same for sub messages. But, we only know we have them
Austin Schuh43c6a352019-09-30 22:22:10 -0700266// all when the structure ends. So, store each sub message in a
267// FieldElement and put them in the table at the end when we finish up
268// each message. Same goes for vectors.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700269class JsonParser {
270 public:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800271 JsonParser(flatbuffers::FlatBufferBuilder *fbb) : fbb_(fbb) {}
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700272 ~JsonParser() {}
273
274 // Parses the json into a flatbuffer. Returns either an empty vector on
275 // error, or a vector with the flatbuffer data in it.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800276 flatbuffers::Offset<flatbuffers::Table> Parse(const std::string_view data,
277 FlatbufferType type) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700278 flatbuffers::uoffset_t end = 0;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800279 bool result = DoParse(type, data, &end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700280
281 if (result) {
282 // On success, finish the table and build the vector.
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800283 return flatbuffers::Offset<flatbuffers::Table>(end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700284 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800285 return flatbuffers::Offset<flatbuffers::Table>(0);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700286 }
287 }
288
289 private:
290 // Setters and getters for in_vector (at the current level of the stack)
291 bool in_vector() const { return stack_.back().in_vector; }
292 void set_in_vector(bool in_vector) { stack_.back().in_vector = in_vector; }
293
294 // Parses the flatbuffer. This is a second method so we can do easier
295 // cleanup at the top level. Returns true on success.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800296 bool DoParse(FlatbufferType type, const std::string_view data,
297 flatbuffers::uoffset_t *table_end);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700298
299 // Adds *_value for the provided field. If we are in a vector, queues the
Alex Perrycb7da4b2019-08-28 19:35:56 -0700300 // data up in vector_elements. Returns true on success.
James Kuszmaul768c4682023-10-12 21:07:16 -0700301 bool AddElement(int field_index, absl::int128 int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700302 bool AddElement(int field_index, double double_value);
303 bool AddElement(int field_index, const ::std::string &data);
304
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700305 // Finishes a vector for the provided field index. Returns true on success.
306 bool FinishVector(int field_index);
307
308 // Pushes an element as part of a vector. Returns true on success.
309 bool PushElement(flatbuffers::ElementaryType elementary_type,
James Kuszmaul768c4682023-10-12 21:07:16 -0700310 absl::int128 int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700311 bool PushElement(flatbuffers::ElementaryType elementary_type,
312 double double_value);
313 bool PushElement(flatbuffers::ElementaryType elementary_type,
314 flatbuffers::Offset<flatbuffers::String> offset_value);
James Kuszmaul768c4682023-10-12 21:07:16 -0700315 bool PushElement(const FlatbufferType &type,
316 const std::vector<uint8_t> &struct_data);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800317 flatbuffers::FlatBufferBuilder *fbb_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700318
319 // This holds the state information that is needed as you recurse into
320 // nested structures.
321 struct FlatBufferContext {
322 // Type of the current type.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800323 FlatbufferType type;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700324 // If true, we are parsing a vector.
325 bool in_vector;
326 // The field index of the current field.
327 int field_index;
328 // Name of the current field.
329 ::std::string field_name;
330
331 // Field elements that need to be inserted.
332 ::std::vector<FieldElement> elements;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700333
334 // For scalar types (not strings, and not nested tables), the vector ends
335 // up being implemented as a start and end, and a block of data. So we
336 // can't just push offsets in as we go. We either need to reproduce the
James Kuszmaul768c4682023-10-12 21:07:16 -0700337 // logic inside flatbuffers, or build up vectors of the data. Vectors
338 // will be a bit of extra stack space, but whatever.
Alex Perrycb7da4b2019-08-28 19:35:56 -0700339 //
340 // Strings and nested structures are vectors of offsets.
341 // into the vector. Once you get to the end, you build up a vector and
342 // push that into the field.
343 ::std::vector<Element> vector_elements;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700344 };
345 ::std::vector<FlatBufferContext> stack_;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700346};
347
Brian Silvermancf4fb662021-02-10 17:54:53 -0800348bool JsonParser::DoParse(FlatbufferType type, const std::string_view data,
Austin Schuhd339a9b2019-10-05 21:33:32 -0700349 flatbuffers::uoffset_t *table_end) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800350 ::std::vector<FlatbufferType> stack;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700351
352 Tokenizer t(data);
353
354 // Main loop. Run until we get an end.
355 while (true) {
356 Tokenizer::TokenType token = t.Next();
357
358 switch (token) {
359 case Tokenizer::TokenType::kEnd:
360 if (stack_.size() != 0) {
Austin Schuh217a9782019-12-21 23:02:50 -0800361 fprintf(stderr, "Failed to unwind stack all the way\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700362 return false;
363 } else {
364 return true;
365 }
366 break;
367 case Tokenizer::TokenType::kError:
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800368 fprintf(stderr, "Encountered an error in the tokenizer\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700369 return false;
370 break;
371
372 case Tokenizer::TokenType::kStartObject: // {
373 if (stack_.size() == 0) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800374 stack_.push_back({type, false, -1, "", {}, {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700375 } else {
376 int field_index = stack_.back().field_index;
377
Brian Silvermancf4fb662021-02-10 17:54:53 -0800378 if (!stack_.back().type.FieldIsSequence(field_index)) {
Austin Schuh217a9782019-12-21 23:02:50 -0800379 fprintf(stderr, "Field '%s' is not a sequence\n",
380 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700381 return false;
382 }
383
James Kuszmaulbb60dfd2023-01-05 17:13:11 -0800384 if (in_vector() != stack_.back().type.FieldIsRepeating(field_index)) {
385 fprintf(stderr,
386 "Field '%s' is%s supposed to be a vector, but is a %s.\n",
387 stack_.back().field_name.c_str(), in_vector() ? " not" : "",
388 in_vector() ? "vector" : "bare object");
389 return false;
390 }
391
Brian Silvermancf4fb662021-02-10 17:54:53 -0800392 stack_.push_back({stack_.back().type.FieldType(field_index),
393 false,
394 -1,
395 "",
396 {},
397 {}});
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700398 }
399 break;
400 case Tokenizer::TokenType::kEndObject: // }
401 if (stack_.size() == 0) {
402 // Somehow we popped more than we pushed. Error.
Austin Schuh217a9782019-12-21 23:02:50 -0800403 fprintf(stderr, "Empty stack\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700404 return false;
405 } else {
James Kuszmaul768c4682023-10-12 21:07:16 -0700406 // End of a nested object! Add it.
407 std::optional<Element> object =
408 WriteObject(stack_.back().type, stack_.back().elements, fbb_);
409 if (!object.has_value()) {
410 return false;
411 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700412
413 // We now want to talk about the parent structure. Pop the child.
414 stack_.pop_back();
415
416 if (stack_.size() == 0) {
James Kuszmaul768c4682023-10-12 21:07:16 -0700417 CHECK_EQ(static_cast<int>(object->type),
418 static_cast<int>(Element::ElementType::OFFSET))
419 << ": JSON parsing only supports parsing flatbuffer tables.";
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700420 // Instead of queueing it up in the stack, return it through the
421 // passed in variable.
James Kuszmaul768c4682023-10-12 21:07:16 -0700422 *table_end = object->offset_element.o;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700423 } else {
424 // And now we can add it.
425 const int field_index = stack_.back().field_index;
426
427 // Do the right thing if we are in a vector.
428 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700429 stack_.back().vector_elements.emplace_back(
James Kuszmaul768c4682023-10-12 21:07:16 -0700430 std::move(object.value()));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700431 } else {
James Kuszmaul768c4682023-10-12 21:07:16 -0700432 stack_.back().elements.emplace_back(field_index,
433 std::move(object.value()));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700434 }
435 }
436 }
437 break;
438
439 case Tokenizer::TokenType::kStartArray: // [
440 if (stack_.size() == 0) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800441 fprintf(stderr,
442 "We don't support an array of structs at the root level.\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700443 return false;
444 }
445 // Sanity check that we aren't trying to make a vector of vectors.
446 if (in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800447 fprintf(stderr, "We don't support vectors of vectors.\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700448 return false;
449 }
450 set_in_vector(true);
451
452 break;
453 case Tokenizer::TokenType::kEndArray: { // ]
454 if (!in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800455 fprintf(stderr, "Encountered ']' with no prior '['.\n");
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700456 return false;
457 }
458
459 const int field_index = stack_.back().field_index;
460
461 if (!FinishVector(field_index)) return false;
462
463 set_in_vector(false);
464 } break;
465
466 case Tokenizer::TokenType::kTrueValue: // true
467 case Tokenizer::TokenType::kFalseValue: // false
468 case Tokenizer::TokenType::kNumberValue: {
469 bool is_int = true;
470 double double_value;
James Kuszmaul768c4682023-10-12 21:07:16 -0700471 absl::int128 int_value;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700472 if (token == Tokenizer::TokenType::kTrueValue) {
473 int_value = 1;
474 } else if (token == Tokenizer::TokenType::kFalseValue) {
475 int_value = 0;
476 } else if (!t.FieldAsInt(&int_value)) {
477 if (t.FieldAsDouble(&double_value)) {
478 is_int = false;
479 } else {
480 fprintf(stderr, "Got a invalid number '%s'\n",
481 t.field_value().c_str());
482 return false;
483 }
484 }
485
486 const int field_index = stack_.back().field_index;
487
488 if (is_int) {
489 // No need to get too stressed about bool vs int. Convert them all.
James Kuszmaul768c4682023-10-12 21:07:16 -0700490 absl::int128 val = int_value;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700491 if (!AddElement(field_index, val)) return false;
492 } else {
493 if (!AddElement(field_index, double_value)) return false;
494 }
495 } break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700496 case Tokenizer::TokenType::kStringValue: // string value
497 {
498 const int field_index = stack_.back().field_index;
499
500 if (!AddElement(field_index, t.field_value())) return false;
501 } break;
502 case Tokenizer::TokenType::kField: // field name
503 {
504 stack_.back().field_name = t.field_name();
Brian Silvermancf4fb662021-02-10 17:54:53 -0800505 stack_.back().field_index =
506 stack_.back().type.FieldIndex(stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700507
508 if (stack_.back().field_index == -1) {
Austin Schuh217a9782019-12-21 23:02:50 -0800509 fprintf(stderr, "Invalid field name '%s'\n",
510 stack_.back().field_name.c_str());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700511 return false;
512 }
513 } break;
514 }
515 }
516 return false;
517}
518
James Kuszmaul768c4682023-10-12 21:07:16 -0700519bool JsonParser::AddElement(int field_index, absl::int128 int_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800520 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800521 fprintf(stderr,
522 "Type and json disagree on if we are in a vector or not (JSON "
523 "believes that we are%s in a vector for field '%s').\n",
524 in_vector() ? "" : " not",
525 stack_.back().type.FieldName(field_index).data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700526 return false;
527 }
528
529 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700530 stack_.back().vector_elements.emplace_back(int_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700531 } else {
532 stack_.back().elements.emplace_back(field_index, int_value);
533 }
534 return true;
535}
536
537bool JsonParser::AddElement(int field_index, double double_value) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800538 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800539 fprintf(stderr,
540 "Type and json disagree on if we are in a vector or not (JSON "
541 "believes that we are%s in a vector for field '%s').\n",
542 in_vector() ? "" : " not",
543 stack_.back().type.FieldName(field_index).data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700544 return false;
545 }
546
547 if (in_vector()) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700548 stack_.back().vector_elements.emplace_back(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700549 } else {
550 stack_.back().elements.emplace_back(field_index, double_value);
551 }
552 return true;
553}
554
555bool JsonParser::AddElement(int field_index, const ::std::string &data) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800556 if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
James Kuszmaulb16f88a2024-01-14 22:08:27 -0800557 fprintf(stderr,
558 "Type and json disagree on if we are in a vector or not (JSON "
559 "believes that we are%s in a vector for field '%s').\n",
560 in_vector() ? "" : " not",
561 stack_.back().type.FieldName(field_index).data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700562 return false;
563 }
564
Alex Perrycb7da4b2019-08-28 19:35:56 -0700565 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800566 stack_.back().type.FieldElementaryType(field_index);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700567 switch (elementary_type) {
568 case flatbuffers::ET_CHAR:
569 case flatbuffers::ET_UCHAR:
570 case flatbuffers::ET_SHORT:
571 case flatbuffers::ET_USHORT:
572 case flatbuffers::ET_INT:
573 case flatbuffers::ET_UINT:
574 case flatbuffers::ET_LONG:
575 case flatbuffers::ET_ULONG:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800576 if (stack_.back().type.FieldIsEnum(field_index)) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700577 // We have an enum.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800578 const FlatbufferType type = stack_.back().type;
579 const FlatbufferType enum_type = type.FieldType(field_index);
580 CHECK(enum_type.IsEnum());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700581
James Kuszmaul768c4682023-10-12 21:07:16 -0700582 const std::optional<absl::int128> int_value = enum_type.EnumValue(data);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700583
Brian Silvermancf4fb662021-02-10 17:54:53 -0800584 if (!int_value) {
585 const std::string_view name = type.FieldName(field_index);
586 fprintf(stderr, "Enum value '%s' not found for field '%.*s'\n",
587 data.c_str(), static_cast<int>(name.size()), name.data());
Alex Perrycb7da4b2019-08-28 19:35:56 -0700588 return false;
589 }
590
591 if (in_vector()) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800592 stack_.back().vector_elements.emplace_back(*int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700593 } else {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800594 stack_.back().elements.emplace_back(field_index, *int_value);
Alex Perrycb7da4b2019-08-28 19:35:56 -0700595 }
596 return true;
597 }
598 case flatbuffers::ET_UTYPE:
599 case flatbuffers::ET_BOOL:
600 case flatbuffers::ET_FLOAT:
601 case flatbuffers::ET_DOUBLE:
602 case flatbuffers::ET_STRING:
603 case flatbuffers::ET_SEQUENCE:
604 break;
605 }
606
607 if (in_vector()) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800608 stack_.back().vector_elements.emplace_back(fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700609 } else {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800610 stack_.back().elements.emplace_back(field_index, fbb_->CreateString(data));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700611 }
612 return true;
613}
614
Brian Silvermancf4fb662021-02-10 17:54:53 -0800615bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
Austin Schuh43c6a352019-09-30 22:22:10 -0700616 ::std::vector<bool> *fields_in_use,
617 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700618 if ((*fields_in_use)[field_element.field_index]) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800619 const std::string_view name = type.FieldName(field_element.field_index);
620 fprintf(stderr, "Duplicate field: '%.*s'\n", static_cast<int>(name.size()),
621 name.data());
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700622 return false;
623 }
624
625 (*fields_in_use)[field_element.field_index] = true;
626
627 switch (field_element.element.type) {
628 case Element::ElementType::INT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800629 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700630 field_element.element.int_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700631 case Element::ElementType::DOUBLE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800632 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700633 field_element.element.double_element, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700634 case Element::ElementType::OFFSET:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800635 return AddSingleElement(type, field_element.field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700636 field_element.element.offset_element, fbb);
James Kuszmaul768c4682023-10-12 21:07:16 -0700637 case Element::ElementType::STRUCT:
638 return AddSingleElement(type, field_element.field_index,
639 field_element.element.struct_data, fbb);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700640 }
641 return false;
642}
643
James Kuszmaul768c4682023-10-12 21:07:16 -0700644bool AddSingleElement(FlatbufferType type, int field_index,
645 absl::int128 int_value,
Brian Silvermancf4fb662021-02-10 17:54:53 -0800646 flatbuffers::FlatBufferBuilder *fbb
Austin Schuh43c6a352019-09-30 22:22:10 -0700647
648) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700649 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
650 static_cast<flatbuffers::voffset_t>(field_index));
651
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700652 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800653 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700654 switch (elementary_type) {
655 case flatbuffers::ET_BOOL:
James Kuszmaul768c4682023-10-12 21:07:16 -0700656 fbb->AddElement<bool>(field_offset, static_cast<bool>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700657 return true;
658 case flatbuffers::ET_CHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700659 fbb->AddElement<int8_t>(field_offset, static_cast<int8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700660 return true;
661 case flatbuffers::ET_UCHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700662 fbb->AddElement<uint8_t>(field_offset, static_cast<uint8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700663 return true;
664 case flatbuffers::ET_SHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700665 fbb->AddElement<int16_t>(field_offset, static_cast<int16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700666 return true;
667 case flatbuffers::ET_USHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700668 fbb->AddElement<uint16_t>(field_offset, static_cast<uint16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700669 return true;
670 case flatbuffers::ET_INT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700671 fbb->AddElement<int32_t>(field_offset, static_cast<int32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700672 return true;
673 case flatbuffers::ET_UINT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700674 fbb->AddElement<uint32_t>(field_offset, static_cast<uint32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700675 return true;
676 case flatbuffers::ET_LONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700677 fbb->AddElement<int64_t>(field_offset, static_cast<int64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700678 return true;
679 case flatbuffers::ET_ULONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700680 fbb->AddElement<uint64_t>(field_offset, static_cast<uint64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700681 return true;
James Kuszmaul768c4682023-10-12 21:07:16 -0700682 // The floating point cases occur when someone specifies an integer in the
683 // JSON for a double field.
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700684 case flatbuffers::ET_FLOAT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700685 fbb->AddElement<float>(field_offset, static_cast<float>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700686 return true;
687 case flatbuffers::ET_DOUBLE:
James Kuszmaul768c4682023-10-12 21:07:16 -0700688 fbb->AddElement<double>(field_offset, static_cast<double>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700689 return true;
690 case flatbuffers::ET_STRING:
691 case flatbuffers::ET_UTYPE:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800692 case flatbuffers::ET_SEQUENCE: {
693 const std::string_view name = type.FieldName(field_index);
694 fprintf(stderr,
695 "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
696 static_cast<int>(name.size()), name.data(),
697 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700698 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800699 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700700 };
701 return false;
702}
703
Brian Silvermancf4fb662021-02-10 17:54:53 -0800704bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
Austin Schuh43c6a352019-09-30 22:22:10 -0700705 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700706 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
707 static_cast<flatbuffers::voffset_t>(field_index));
708
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700709 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800710 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700711 switch (elementary_type) {
712 case flatbuffers::ET_UTYPE:
713 case flatbuffers::ET_BOOL:
714 case flatbuffers::ET_CHAR:
715 case flatbuffers::ET_UCHAR:
716 case flatbuffers::ET_SHORT:
717 case flatbuffers::ET_USHORT:
718 case flatbuffers::ET_INT:
719 case flatbuffers::ET_UINT:
720 case flatbuffers::ET_LONG:
721 case flatbuffers::ET_ULONG:
722 case flatbuffers::ET_STRING:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800723 case flatbuffers::ET_SEQUENCE: {
724 const std::string_view name = type.FieldName(field_index);
725 fprintf(stderr,
726 "Mismatched type for field '%.*s'. Got: double, expected %s\n",
727 static_cast<int>(name.size()), name.data(),
728 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700729 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800730 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700731 case flatbuffers::ET_FLOAT:
Brian Silverman69069232021-11-10 12:26:52 -0800732 fbb->AddElement<float>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700733 return true;
734 case flatbuffers::ET_DOUBLE:
Brian Silverman69069232021-11-10 12:26:52 -0800735 fbb->AddElement<double>(field_offset, double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700736 return true;
737 }
738 return false;
739}
James Kuszmaul768c4682023-10-12 21:07:16 -0700740
Brian Silvermancf4fb662021-02-10 17:54:53 -0800741bool AddSingleElement(FlatbufferType type, int field_index,
Austin Schuh43c6a352019-09-30 22:22:10 -0700742 flatbuffers::Offset<flatbuffers::String> offset_element,
743 flatbuffers::FlatBufferBuilder *fbb) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700744 flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
745 static_cast<flatbuffers::voffset_t>(field_index));
746
747 // Vectors will always be Offset<>'s.
Brian Silvermancf4fb662021-02-10 17:54:53 -0800748 if (type.FieldIsRepeating(field_index)) {
Austin Schuh43c6a352019-09-30 22:22:10 -0700749 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700750 return true;
751 }
752
753 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800754 type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700755 switch (elementary_type) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700756 case flatbuffers::ET_CHAR:
757 case flatbuffers::ET_UCHAR:
758 case flatbuffers::ET_SHORT:
759 case flatbuffers::ET_USHORT:
760 case flatbuffers::ET_INT:
761 case flatbuffers::ET_UINT:
762 case flatbuffers::ET_LONG:
763 case flatbuffers::ET_ULONG:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700764 case flatbuffers::ET_UTYPE:
765 case flatbuffers::ET_BOOL:
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700766 case flatbuffers::ET_FLOAT:
Brian Silvermancf4fb662021-02-10 17:54:53 -0800767 case flatbuffers::ET_DOUBLE: {
768 const std::string_view name = type.FieldName(field_index);
769 fprintf(stderr,
770 "Mismatched type for field '%.*s'. Got: string, expected %s\n",
771 static_cast<int>(name.size()), name.data(),
772 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700773 return false;
Brian Silvermancf4fb662021-02-10 17:54:53 -0800774 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700775 case flatbuffers::ET_STRING:
Alex Perrycb7da4b2019-08-28 19:35:56 -0700776 case flatbuffers::ET_SEQUENCE:
Austin Schuh43c6a352019-09-30 22:22:10 -0700777 fbb->AddOffset(field_offset, offset_element);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700778 return true;
779 }
780 return false;
781}
782
James Kuszmaul768c4682023-10-12 21:07:16 -0700783bool AddSingleElement(FlatbufferType type, int field_index,
784 const std::vector<uint8_t> &data,
785 flatbuffers::FlatBufferBuilder *fbb) {
786 // Structs are always inline.
787 // We have to do somewhat manual serialization to get the struct into place,
788 // since the regular FlatBufferBuilder assumes that you will know the type of
789 // the struct that you are constructing at compile time.
790 fbb->Align(type.FieldType(field_index).Alignment());
791 fbb->PushBytes(data.data(), data.size());
792 fbb->AddStructOffset(flatbuffers::FieldIndexToOffset(
793 static_cast<flatbuffers::voffset_t>(field_index)),
794 fbb->GetSize());
795 return true;
796}
797
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700798bool JsonParser::FinishVector(int field_index) {
Brian Silvermancf4fb662021-02-10 17:54:53 -0800799 // Vectors have a start (unfortunately which needs to know the size)
James Kuszmaul65541cb2022-11-08 14:53:47 -0800800 const size_t inline_size = stack_.back().type.FieldInlineSize(field_index);
James Kuszmaul768c4682023-10-12 21:07:16 -0700801 const size_t alignment = stack_.back().type.FieldInlineAlignment(field_index);
James Kuszmaul65541cb2022-11-08 14:53:47 -0800802 fbb_->StartVector(stack_.back().vector_elements.size(), inline_size,
James Kuszmaul768c4682023-10-12 21:07:16 -0700803 /*align=*/alignment);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700804
805 const flatbuffers::ElementaryType elementary_type =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800806 stack_.back().type.FieldElementaryType(field_index);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700807
808 // Then the data (in reverse order for some reason...)
Alex Perrycb7da4b2019-08-28 19:35:56 -0700809 for (size_t i = stack_.back().vector_elements.size(); i > 0;) {
810 const Element &element = stack_.back().vector_elements[--i];
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700811 switch (element.type) {
812 case Element::ElementType::INT:
813 if (!PushElement(elementary_type, element.int_element)) return false;
814 break;
815 case Element::ElementType::DOUBLE:
816 if (!PushElement(elementary_type, element.double_element)) return false;
817 break;
818 case Element::ElementType::OFFSET:
819 if (!PushElement(elementary_type, element.offset_element)) return false;
820 break;
James Kuszmaul768c4682023-10-12 21:07:16 -0700821 case Element::ElementType::STRUCT:
822 if (!PushElement(stack_.back().type.FieldType(field_index),
823 element.struct_data))
824 return false;
825 break;
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700826 }
827 }
828
829 // Then an End which is placed into the buffer the same as any other offset.
830 stack_.back().elements.emplace_back(
831 field_index, flatbuffers::Offset<flatbuffers::String>(
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800832 fbb_->EndVector(stack_.back().vector_elements.size())));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700833 stack_.back().vector_elements.clear();
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700834 return true;
835}
836
837bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
James Kuszmaul768c4682023-10-12 21:07:16 -0700838 absl::int128 int_value) {
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700839 switch (elementary_type) {
840 case flatbuffers::ET_BOOL:
James Kuszmaul768c4682023-10-12 21:07:16 -0700841 fbb_->PushElement<bool>(static_cast<bool>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700842 return true;
843 case flatbuffers::ET_CHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700844 fbb_->PushElement<int8_t>(static_cast<int8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700845 return true;
846 case flatbuffers::ET_UCHAR:
James Kuszmaul768c4682023-10-12 21:07:16 -0700847 fbb_->PushElement<uint8_t>(static_cast<uint8_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700848 return true;
849 case flatbuffers::ET_SHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700850 fbb_->PushElement<int16_t>(static_cast<int16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700851 return true;
852 case flatbuffers::ET_USHORT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700853 fbb_->PushElement<uint16_t>(static_cast<uint16_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700854 return true;
855 case flatbuffers::ET_INT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700856 fbb_->PushElement<int32_t>(static_cast<int32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700857 return true;
858 case flatbuffers::ET_UINT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700859 fbb_->PushElement<uint32_t>(static_cast<uint32_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700860 return true;
861 case flatbuffers::ET_LONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700862 fbb_->PushElement<int64_t>(static_cast<int64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700863 return true;
864 case flatbuffers::ET_ULONG:
James Kuszmaul768c4682023-10-12 21:07:16 -0700865 fbb_->PushElement<uint64_t>(static_cast<uint64_t>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700866 return true;
867 case flatbuffers::ET_FLOAT:
James Kuszmaul768c4682023-10-12 21:07:16 -0700868 fbb_->PushElement<float>(static_cast<float>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700869 return true;
870 case flatbuffers::ET_DOUBLE:
James Kuszmaul768c4682023-10-12 21:07:16 -0700871 fbb_->PushElement<double>(static_cast<double>(int_value));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700872 return true;
873 case flatbuffers::ET_STRING:
874 case flatbuffers::ET_UTYPE:
875 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800876 fprintf(stderr,
877 "Mismatched type for field '%s'. Got: integer, expected %s\n",
878 stack_.back().field_name.c_str(),
879 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700880 return false;
881 };
882 return false;
883}
884
885bool JsonParser::PushElement(flatbuffers::ElementaryType elementary_type,
886 double double_value) {
887 switch (elementary_type) {
888 case flatbuffers::ET_UTYPE:
889 case flatbuffers::ET_BOOL:
890 case flatbuffers::ET_CHAR:
891 case flatbuffers::ET_UCHAR:
892 case flatbuffers::ET_SHORT:
893 case flatbuffers::ET_USHORT:
894 case flatbuffers::ET_INT:
895 case flatbuffers::ET_UINT:
896 case flatbuffers::ET_LONG:
897 case flatbuffers::ET_ULONG:
898 case flatbuffers::ET_STRING:
899 case flatbuffers::ET_SEQUENCE:
Austin Schuh217a9782019-12-21 23:02:50 -0800900 fprintf(stderr,
901 "Mismatched type for field '%s'. Got: double, expected %s\n",
902 stack_.back().field_name.c_str(),
903 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700904 return false;
905 case flatbuffers::ET_FLOAT:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800906 fbb_->PushElement<float>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700907 return true;
908 case flatbuffers::ET_DOUBLE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800909 fbb_->PushElement<double>(double_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700910 return true;
911 }
912 return false;
913}
914
James Kuszmaul768c4682023-10-12 21:07:16 -0700915bool JsonParser::PushElement(const FlatbufferType &type,
916 const std::vector<uint8_t> &struct_data) {
917 // To add a struct to a vector, we just need to get the relevant bytes pushed
918 // straight into the builder. The FlatBufferBuilder normally expects that you
919 // will know the type of your struct at compile-time, so doesn't have a
920 // first-class way to do this.
921 fbb_->Align(type.Alignment());
922 fbb_->PushBytes(struct_data.data(), struct_data.size());
923 return true;
924}
925
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700926bool JsonParser::PushElement(
927 flatbuffers::ElementaryType elementary_type,
928 flatbuffers::Offset<flatbuffers::String> offset_value) {
929 switch (elementary_type) {
930 case flatbuffers::ET_UTYPE:
931 case flatbuffers::ET_BOOL:
932 case flatbuffers::ET_CHAR:
933 case flatbuffers::ET_UCHAR:
934 case flatbuffers::ET_SHORT:
935 case flatbuffers::ET_USHORT:
936 case flatbuffers::ET_INT:
937 case flatbuffers::ET_UINT:
938 case flatbuffers::ET_LONG:
939 case flatbuffers::ET_ULONG:
940 case flatbuffers::ET_FLOAT:
941 case flatbuffers::ET_DOUBLE:
Austin Schuh217a9782019-12-21 23:02:50 -0800942 fprintf(stderr,
943 "Mismatched type for field '%s'. Got: sequence, expected %s\n",
944 stack_.back().field_name.c_str(),
945 ElementaryTypeName(elementary_type));
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700946 return false;
947 case flatbuffers::ET_STRING:
948 case flatbuffers::ET_SEQUENCE:
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800949 fbb_->PushElement(offset_value);
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700950 return true;
951 }
952 return false;
953}
954
955} // namespace
956
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800957flatbuffers::Offset<flatbuffers::Table> JsonToFlatbuffer(
Brian Silvermancf4fb662021-02-10 17:54:53 -0800958 const std::string_view data, FlatbufferType type,
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800959 flatbuffers::FlatBufferBuilder *fbb) {
960 JsonParser p(fbb);
Brian Silvermancf4fb662021-02-10 17:54:53 -0800961 return p.Parse(data, type);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800962}
963
Brian Silvermancf4fb662021-02-10 17:54:53 -0800964flatbuffers::DetachedBuffer JsonToFlatbuffer(const std::string_view data,
965 FlatbufferType type) {
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800966 flatbuffers::FlatBufferBuilder fbb;
Austin Schuhd7b15da2020-02-17 15:06:11 -0800967 fbb.ForceDefaults(true);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800968
969 const flatbuffers::Offset<flatbuffers::Table> result =
Brian Silvermancf4fb662021-02-10 17:54:53 -0800970 JsonToFlatbuffer(data, type, &fbb);
Austin Schuh53b1a6f2020-01-10 19:31:28 -0800971 if (result.o != 0) {
972 fbb.Finish(result);
973
974 return fbb.Release();
975 } else {
976 // Otherwise return an empty vector.
977 return flatbuffers::DetachedBuffer();
978 }
Austin Schuh3e95e5d2019-09-20 00:08:54 -0700979}
980
Austin Schuhd3936202020-04-07 20:11:07 -0700981namespace {
982
983// A visitor which manages skipping the contents of vectors that are longer than
984// a specified threshold.
985class TruncatingStringVisitor : public flatbuffers::IterationVisitor {
986 public:
987 TruncatingStringVisitor(size_t max_vector_size, std::string delimiter,
988 bool quotes, std::string indent, bool vdelimited)
989 : max_vector_size_(max_vector_size),
990 to_string_(delimiter, quotes, indent, vdelimited) {}
991 ~TruncatingStringVisitor() override {}
992
993 void StartSequence() override {
994 if (should_skip()) return;
995 to_string_.StartSequence();
996 }
997 void EndSequence() override {
998 if (should_skip()) return;
999 to_string_.EndSequence();
1000 }
1001 void Field(size_t field_idx, size_t set_idx, flatbuffers::ElementaryType type,
Austin Schuh7c75e582020-11-14 16:41:18 -08001002 bool is_repeating, const flatbuffers::TypeTable *type_table,
Austin Schuhd3936202020-04-07 20:11:07 -07001003 const char *name, const uint8_t *val) override {
1004 if (should_skip()) return;
Austin Schuh7c75e582020-11-14 16:41:18 -08001005 to_string_.Field(field_idx, set_idx, type, is_repeating, type_table, name,
Austin Schuhd3936202020-04-07 20:11:07 -07001006 val);
1007 }
1008 void UType(uint8_t value, const char *name) override {
1009 if (should_skip()) return;
1010 to_string_.UType(value, name);
1011 }
1012 void Bool(bool value) override {
1013 if (should_skip()) return;
1014 to_string_.Bool(value);
1015 }
1016 void Char(int8_t value, const char *name) override {
1017 if (should_skip()) return;
1018 to_string_.Char(value, name);
1019 }
1020 void UChar(uint8_t value, const char *name) override {
1021 if (should_skip()) return;
1022 to_string_.UChar(value, name);
1023 }
1024 void Short(int16_t value, const char *name) override {
1025 if (should_skip()) return;
1026 to_string_.Short(value, name);
1027 }
1028 void UShort(uint16_t value, const char *name) override {
1029 if (should_skip()) return;
1030 to_string_.UShort(value, name);
1031 }
1032 void Int(int32_t value, const char *name) override {
1033 if (should_skip()) return;
1034 to_string_.Int(value, name);
1035 }
1036 void UInt(uint32_t value, const char *name) override {
1037 if (should_skip()) return;
1038 to_string_.UInt(value, name);
1039 }
1040 void Long(int64_t value) override {
1041 if (should_skip()) return;
1042 to_string_.Long(value);
1043 }
1044 void ULong(uint64_t value) override {
1045 if (should_skip()) return;
1046 to_string_.ULong(value);
1047 }
1048 void Float(float value) override {
1049 if (should_skip()) return;
1050 to_string_.Float(value);
1051 }
1052 void Double(double value) override {
1053 if (should_skip()) return;
1054 to_string_.Double(value);
1055 }
1056 void String(const flatbuffers::String *value) override {
1057 if (should_skip()) return;
1058 to_string_.String(value);
1059 }
1060 void Unknown(const uint8_t *value) override {
1061 if (should_skip()) return;
1062 to_string_.Unknown(value);
1063 }
1064 void Element(size_t i, flatbuffers::ElementaryType type,
1065 const flatbuffers::TypeTable *type_table,
1066 const uint8_t *val) override {
1067 if (should_skip()) return;
1068 to_string_.Element(i, type, type_table, val);
1069 }
1070
1071 virtual void StartVector(size_t size) override {
1072 if (should_skip()) {
1073 ++skip_levels_;
1074 return;
1075 }
1076 if (size > max_vector_size_) {
1077 ++skip_levels_;
Austin Schuh041fe9f2021-10-16 23:01:15 -07001078 to_string_.s += "[ \"... " + std::to_string(size) + " elements ...\" ]";
Austin Schuhd3936202020-04-07 20:11:07 -07001079 return;
1080 }
1081 to_string_.StartVector(size);
1082 }
1083 virtual void EndVector() override {
1084 if (should_skip()) {
1085 --skip_levels_;
1086 return;
1087 }
1088 to_string_.EndVector();
1089 }
1090
1091 std::string &string() { return to_string_.s; }
1092
1093 private:
1094 bool should_skip() const { return skip_levels_ > 0; }
1095
1096 const size_t max_vector_size_;
1097 flatbuffers::ToStringVisitor to_string_;
1098 int skip_levels_ = 0;
1099};
1100
1101} // namespace
1102
Austin Schuhe93d8642019-10-13 15:27:07 -07001103::std::string TableFlatbufferToJson(const flatbuffers::Table *t,
1104 const ::flatbuffers::TypeTable *typetable,
Ravago Jonescf453ab2020-05-06 21:14:53 -07001105 JsonOptions json_options) {
Austin Schuhe93d8642019-10-13 15:27:07 -07001106 // It is pretty common to get passed in a nullptr when a test fails. Rather
1107 // than CHECK, return a more user friendly result.
1108 if (t == nullptr) {
1109 return "null";
1110 }
Ravago Jonescf453ab2020-05-06 21:14:53 -07001111 TruncatingStringVisitor tostring_visitor(
1112 json_options.max_vector_size, json_options.multi_line ? "\n" : " ", true,
1113 json_options.multi_line ? " " : "", json_options.multi_line);
Austin Schuhe93d8642019-10-13 15:27:07 -07001114 flatbuffers::IterateObject(reinterpret_cast<const uint8_t *>(t), typetable,
1115 &tostring_visitor);
Austin Schuhd3936202020-04-07 20:11:07 -07001116 return tostring_visitor.string();
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001117}
1118
Austin Schuh3e95e5d2019-09-20 00:08:54 -07001119} // namespace aos