blob: 036a830c7c35ba256ececc7104ff392d85843089 [file] [log] [blame]
Austin Schuhd3936202020-04-07 20:11:07 -07001#include <cmath>
Tyler Chatow5e369a42019-11-23 11:57:31 -08002#include <iostream>
3#include <sstream>
4
5#include "aos/json_to_flatbuffer.h"
6
7namespace aos {
8
9namespace {
10
11using reflection::BaseType;
12
13void IntToString(int64_t val, reflection::BaseType type,
14 std::stringstream *out) {
15 switch (type) {
16 case BaseType::Bool:
17 *out << (val ? "true" : "false");
18 break;
19 case BaseType::UByte:
20 *out << std::to_string(static_cast<uint8_t>(val));
21 break;
22 case BaseType::Byte:
23 *out << std::to_string(static_cast<int8_t>(val));
24 break;
25 case BaseType::Short:
26 *out << static_cast<int16_t>(val);
27 break;
28 case BaseType::UShort:
29 *out << static_cast<uint16_t>(val);
30 break;
31 case BaseType::Int:
32 *out << static_cast<int32_t>(val);
33 break;
34 case BaseType::UInt:
35 *out << static_cast<uint32_t>(val);
36 break;
37 case BaseType::Long:
38 *out << static_cast<int64_t>(val);
39 break;
40 case BaseType::ULong:
41 *out << static_cast<uint64_t>(val);
42 break;
43 default:
44 *out << "null";
45 }
46}
47
48void FloatToString(double val, reflection::BaseType type,
49 std::stringstream *out) {
Austin Schuhd3936202020-04-07 20:11:07 -070050 if (std::isnan(val)) {
51 *out << "null";
52 return;
53 }
Tyler Chatow5e369a42019-11-23 11:57:31 -080054 switch (type) {
55 case BaseType::Float:
56 out->precision(std::numeric_limits<float>::digits10);
57 *out << static_cast<float>(val);
58 break;
59 case BaseType::Double:
60 out->precision(std::numeric_limits<double>::digits10);
61 *out << val;
62 break;
63 default:
64 *out << "null";
65 }
66}
67
68template <typename ObjT>
69void ObjectToString(
70 const reflection::Object *obj,
71 const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
72 const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
Austin Schuhd3936202020-04-07 20:11:07 -070073 const ObjT *object, size_t max_vector_size, std::stringstream *out);
Tyler Chatow5e369a42019-11-23 11:57:31 -080074
75// Get enum value name
76const char *EnumToString(
77 int64_t enum_value,
78 const flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>>
79 *values) {
80 // Replace with binary search? Enum values are pre-sorted.
81 for (auto iter = values->begin(); iter != values->end(); iter++) {
82 if (enum_value == iter->value()) {
83 return iter->name()->c_str();
84 }
85 }
86 return nullptr;
87}
88
89// Convert integer to string, checking if it is an enum.
90void IntOrEnumToString(
91 int64_t val, const reflection::Type *type,
92 const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
93 std::stringstream *out) {
94 // Check if integer is an enum and print string, otherwise fallback to
95 // printing as int.
96 if (type->index() > -1 && type->index() < (int32_t)enums->size()) {
97 const reflection::Enum *enum_props = enums->Get(type->index());
98 if (!enum_props->is_union()) {
99 const char *value_string = EnumToString(val, enum_props->values());
100
101 if (value_string != nullptr) {
102 *out << '"' << value_string << '"';
Austin Schuhd3936202020-04-07 20:11:07 -0700103 } else {
104 *out << val;
Tyler Chatow5e369a42019-11-23 11:57:31 -0800105 }
106 }
107 } else {
108 if (type->base_type() == BaseType::Vector ||
109 type->base_type() == BaseType::Array) {
110 IntToString(val, type->element(), out);
111 } else {
112 IntToString(val, type->base_type(), out);
113 }
114 }
115}
116
117// Print field in flatbuffer table. Field must be populated.
118template <typename ObjT>
119void FieldToString(
120 const ObjT *table, const reflection::Field *field,
121 const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
122 const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
Austin Schuhd3936202020-04-07 20:11:07 -0700123 size_t max_vector_size, std::stringstream *out) {
Tyler Chatow5e369a42019-11-23 11:57:31 -0800124 const reflection::Type *type = field->type();
125
126 switch (type->base_type()) {
127 case BaseType::Bool:
128 case BaseType::UByte:
129 case BaseType::Byte:
130 case BaseType::Short:
131 case BaseType::UShort:
132 case BaseType::Int:
133 case BaseType::UInt:
134 case BaseType::Long:
135 case BaseType::ULong:
136 IntOrEnumToString(GetAnyFieldI(*table, *field), type, enums, out);
137 break;
138 case BaseType::Float:
139 case BaseType::Double:
140 FloatToString(GetAnyFieldF(*table, *field), type->base_type(), out);
141 break;
142 case BaseType::String:
143 if constexpr (std::is_same<flatbuffers::Table, ObjT>()) {
144 std::string str = flatbuffers::GetFieldS(*table, *field)->str();
145 std::string out_str;
146 out_str.reserve(str.size());
147 for (char c : str) {
148 // out_str += c;
149 switch (c) {
150 case '"':
151 out_str += "\\\"";
152 break;
153 case '\\':
154 out_str += "\\\\";
155 break;
156 case '\b':
157 out_str += "\\b";
158 break;
159 case '\f':
160 out_str += "\\f";
161 break;
162 case '\n':
163 out_str += "\\n";
164 break;
165 case '\r':
166 out_str += "\\r";
167 break;
168 case '\t':
169 out_str += "\\t";
170 break;
171 default:
172 out_str += c;
173 }
174 }
175 *out << '"' << out_str << '"';
176 } else {
177 *out << "null";
178 }
179 break;
180 case BaseType::Vector: {
181 if constexpr (std::is_same<flatbuffers::Table, ObjT>()) {
182 const flatbuffers::VectorOfAny *vector =
183 flatbuffers::GetFieldAnyV(*table, *field);
184 reflection::BaseType elem_type = type->element();
185
Austin Schuhd3936202020-04-07 20:11:07 -0700186 if (vector->size() > max_vector_size) {
187 *out << "[ ... " << vector->size() << " elements ... ]";
188 break;
189 }
Tyler Chatow5e369a42019-11-23 11:57:31 -0800190 *out << '[';
191 for (flatbuffers::uoffset_t i = 0; i < vector->size(); ++i) {
192 if (i != 0) {
193 *out << ", ";
194 }
195 if (flatbuffers::IsInteger(elem_type)) {
196 IntOrEnumToString(
197 flatbuffers::GetAnyVectorElemI(vector, elem_type, i), type,
198 enums, out);
199 } else if (flatbuffers::IsFloat(elem_type)) {
200 FloatToString(flatbuffers::GetAnyVectorElemF(vector, elem_type, i),
201 elem_type, out);
202 } else if (elem_type == BaseType::String) {
203 *out << '"' << flatbuffers::GetAnyVectorElemS(vector, elem_type, i)
204 << '"';
205 } else if (elem_type == BaseType::Obj) {
206 if (type->index() > -1 &&
207 type->index() < (int32_t)objects->size()) {
208 if (objects->Get(type->index())->is_struct()) {
209 ObjectToString(
210 objects->Get(type->index()), objects, enums,
211 flatbuffers::GetAnyVectorElemAddressOf<
212 const flatbuffers::Struct>(
213 vector, i, objects->Get(type->index())->bytesize()),
Austin Schuhd3936202020-04-07 20:11:07 -0700214 max_vector_size,
Tyler Chatow5e369a42019-11-23 11:57:31 -0800215 out);
216 } else {
217 ObjectToString(objects->Get(type->index()), objects, enums,
218 flatbuffers::GetAnyVectorElemPointer<
219 const flatbuffers::Table>(vector, i),
Austin Schuhd3936202020-04-07 20:11:07 -0700220 max_vector_size,
Tyler Chatow5e369a42019-11-23 11:57:31 -0800221 out);
222 }
223 }
224 }
225 }
226 *out << ']';
227 } else {
228 *out << "null";
229 }
230 } break;
231 case BaseType::Obj: {
232 if (type->index() > -1 && type->index() < (int32_t)objects->size()) {
233 if (objects->Get(type->index())->is_struct()) {
234 ObjectToString(objects->Get(type->index()), objects, enums,
Austin Schuhd3936202020-04-07 20:11:07 -0700235 flatbuffers::GetFieldStruct(*table, *field), max_vector_size, out);
Tyler Chatow5e369a42019-11-23 11:57:31 -0800236 } else if constexpr (std::is_same<flatbuffers::Table, ObjT>()) {
237 ObjectToString(objects->Get(type->index()), objects, enums,
Austin Schuhd3936202020-04-07 20:11:07 -0700238 flatbuffers::GetFieldT(*table, *field), max_vector_size,out);
Tyler Chatow5e369a42019-11-23 11:57:31 -0800239 }
240 } else {
241 *out << "null";
242 }
243 } break;
244 default:
245 *out << "null";
246 }
247}
248
249// Prints flatbuffer table or struct given list of possible child objects and
250// enums. Prints "null" if the child object type is not found.
251template <typename ObjT>
252void ObjectToString(
253 const reflection::Object *obj,
254 const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
255 const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
Austin Schuhd3936202020-04-07 20:11:07 -0700256 const ObjT *object, size_t max_vector_size, std::stringstream *out) {
Tyler Chatow5e369a42019-11-23 11:57:31 -0800257 static_assert(std::is_same<flatbuffers::Table, ObjT>() ||
258 std::is_same<flatbuffers::Struct, ObjT>(),
259 "Type must be either flatbuffer table or struct");
260 bool print_sep = false;
261 *out << '{';
262 for (const reflection::Field *field : *obj->fields()) {
263 // Check whether this object has the field populated (even for structs,
264 // which should have all fields populated)
265 if (object->GetAddressOf(field->offset())) {
266 if (print_sep) {
267 *out << ", ";
268 } else {
269 print_sep = true;
270 }
271 *out << '"' << field->name()->c_str() << "\": ";
Austin Schuhd3936202020-04-07 20:11:07 -0700272 FieldToString(object, field, objects, enums, max_vector_size, out);
Tyler Chatow5e369a42019-11-23 11:57:31 -0800273 }
274 }
275 *out << '}';
276}
277
278} // namespace
279
280std::string FlatbufferToJson(const reflection::Schema *schema,
Austin Schuhd3936202020-04-07 20:11:07 -0700281 const uint8_t *data, size_t max_vector_size) {
Tyler Chatow5e369a42019-11-23 11:57:31 -0800282 const flatbuffers::Table *table = flatbuffers::GetAnyRoot(data);
283
284 const reflection::Object *obj = schema->root_table();
285
286 std::stringstream out;
287
Austin Schuhd3936202020-04-07 20:11:07 -0700288 ObjectToString(obj, schema->objects(), schema->enums(), table,
289 max_vector_size, &out);
Tyler Chatow5e369a42019-11-23 11:57:31 -0800290
291 return out.str();
292}
293} // namespace aos