github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/executor/_include/flatbuffers/minireflect.h (about) 1 /* 2 * Copyright 2017 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef FLATBUFFERS_MINIREFLECT_H_ 18 #define FLATBUFFERS_MINIREFLECT_H_ 19 20 #include "flatbuffers/flatbuffers.h" 21 #include "flatbuffers/util.h" 22 23 namespace flatbuffers { 24 25 // Utilities that can be used with the "mini reflection" tables present 26 // in generated code with --reflect-types (only types) or --reflect-names 27 // (also names). 28 // This allows basic reflection functionality such as pretty-printing 29 // that does not require the use of the schema parser or loading of binary 30 // schema files at runtime (reflection.h). 31 32 // For any of the functions below that take `const TypeTable *`, you pass 33 // `FooTypeTable()` if the type of the root is `Foo`. 34 35 // First, a generic iterator that can be used by multiple algorithms. 36 37 struct IterationVisitor { 38 // These mark the scope of a table or struct. 39 virtual void StartSequence() {} 40 virtual void EndSequence() {} 41 // Called for each field regardless of whether it is present or not. 42 // If not present, val == nullptr. set_idx is the index of all set fields. 43 virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/, 44 ElementaryType /*type*/, bool /*is_vector*/, 45 const TypeTable * /*type_table*/, const char * /*name*/, 46 const uint8_t * /*val*/) {} 47 // Called for a value that is actually present, after a field, or as part 48 // of a vector. 49 virtual void UType(uint8_t, const char *) {} 50 virtual void Bool(bool) {} 51 virtual void Char(int8_t, const char *) {} 52 virtual void UChar(uint8_t, const char *) {} 53 virtual void Short(int16_t, const char *) {} 54 virtual void UShort(uint16_t, const char *) {} 55 virtual void Int(int32_t, const char *) {} 56 virtual void UInt(uint32_t, const char *) {} 57 virtual void Long(int64_t) {} 58 virtual void ULong(uint64_t) {} 59 virtual void Float(float) {} 60 virtual void Double(double) {} 61 virtual void String(const String *) {} 62 virtual void Unknown(const uint8_t *) {} // From a future version. 63 // These mark the scope of a vector. 64 virtual void StartVector() {} 65 virtual void EndVector() {} 66 virtual void Element(size_t /*i*/, ElementaryType /*type*/, 67 const TypeTable * /*type_table*/, 68 const uint8_t * /*val*/) {} 69 virtual ~IterationVisitor() {} 70 }; 71 72 inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) { 73 switch (type) { 74 case ET_UTYPE: 75 case ET_BOOL: 76 case ET_CHAR: 77 case ET_UCHAR: return 1; 78 case ET_SHORT: 79 case ET_USHORT: return 2; 80 case ET_INT: 81 case ET_UINT: 82 case ET_FLOAT: 83 case ET_STRING: return 4; 84 case ET_LONG: 85 case ET_ULONG: 86 case ET_DOUBLE: return 8; 87 case ET_SEQUENCE: 88 switch (type_table->st) { 89 case ST_TABLE: 90 case ST_UNION: return 4; 91 case ST_STRUCT: 92 return static_cast<size_t>(type_table->values[type_table->num_elems]); 93 default: FLATBUFFERS_ASSERT(false); return 1; 94 } 95 default: FLATBUFFERS_ASSERT(false); return 1; 96 } 97 } 98 99 inline int64_t LookupEnum(int64_t enum_val, const int64_t *values, 100 size_t num_values) { 101 if (!values) return enum_val; 102 for (size_t i = 0; i < num_values; i++) { 103 if (enum_val == values[i]) return static_cast<int64_t>(i); 104 } 105 return -1; // Unknown enum value. 106 } 107 108 template<typename T> const char *EnumName(T tval, const TypeTable *type_table) { 109 if (!type_table || !type_table->names) return nullptr; 110 auto i = LookupEnum(static_cast<int64_t>(tval), type_table->values, 111 type_table->num_elems); 112 if (i >= 0 && i < static_cast<int64_t>(type_table->num_elems)) { 113 return type_table->names[i]; 114 } 115 return nullptr; 116 } 117 118 void IterateObject(const uint8_t *obj, const TypeTable *type_table, 119 IterationVisitor *visitor); 120 121 inline void IterateValue(ElementaryType type, const uint8_t *val, 122 const TypeTable *type_table, const uint8_t *prev_val, 123 soffset_t vector_index, IterationVisitor *visitor) { 124 switch (type) { 125 case ET_UTYPE: { 126 auto tval = ReadScalar<uint8_t>(val); 127 visitor->UType(tval, EnumName(tval, type_table)); 128 break; 129 } 130 case ET_BOOL: { 131 visitor->Bool(ReadScalar<uint8_t>(val) != 0); 132 break; 133 } 134 case ET_CHAR: { 135 auto tval = ReadScalar<int8_t>(val); 136 visitor->Char(tval, EnumName(tval, type_table)); 137 break; 138 } 139 case ET_UCHAR: { 140 auto tval = ReadScalar<uint8_t>(val); 141 visitor->UChar(tval, EnumName(tval, type_table)); 142 break; 143 } 144 case ET_SHORT: { 145 auto tval = ReadScalar<int16_t>(val); 146 visitor->Short(tval, EnumName(tval, type_table)); 147 break; 148 } 149 case ET_USHORT: { 150 auto tval = ReadScalar<uint16_t>(val); 151 visitor->UShort(tval, EnumName(tval, type_table)); 152 break; 153 } 154 case ET_INT: { 155 auto tval = ReadScalar<int32_t>(val); 156 visitor->Int(tval, EnumName(tval, type_table)); 157 break; 158 } 159 case ET_UINT: { 160 auto tval = ReadScalar<uint32_t>(val); 161 visitor->UInt(tval, EnumName(tval, type_table)); 162 break; 163 } 164 case ET_LONG: { 165 visitor->Long(ReadScalar<int64_t>(val)); 166 break; 167 } 168 case ET_ULONG: { 169 visitor->ULong(ReadScalar<uint64_t>(val)); 170 break; 171 } 172 case ET_FLOAT: { 173 visitor->Float(ReadScalar<float>(val)); 174 break; 175 } 176 case ET_DOUBLE: { 177 visitor->Double(ReadScalar<double>(val)); 178 break; 179 } 180 case ET_STRING: { 181 val += ReadScalar<uoffset_t>(val); 182 visitor->String(reinterpret_cast<const String *>(val)); 183 break; 184 } 185 case ET_SEQUENCE: { 186 switch (type_table->st) { 187 case ST_TABLE: 188 val += ReadScalar<uoffset_t>(val); 189 IterateObject(val, type_table, visitor); 190 break; 191 case ST_STRUCT: IterateObject(val, type_table, visitor); break; 192 case ST_UNION: { 193 val += ReadScalar<uoffset_t>(val); 194 FLATBUFFERS_ASSERT(prev_val); 195 auto union_type = *prev_val; // Always a uint8_t. 196 if (vector_index >= 0) { 197 auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val); 198 union_type = type_vec->Get(static_cast<uoffset_t>(vector_index)); 199 } 200 auto type_code_idx = 201 LookupEnum(union_type, type_table->values, type_table->num_elems); 202 if (type_code_idx >= 0 && 203 type_code_idx < static_cast<int32_t>(type_table->num_elems)) { 204 auto type_code = type_table->type_codes[type_code_idx]; 205 switch (type_code.base_type) { 206 case ET_SEQUENCE: { 207 auto ref = type_table->type_refs[type_code.sequence_ref](); 208 IterateObject(val, ref, visitor); 209 break; 210 } 211 case ET_STRING: 212 visitor->String(reinterpret_cast<const String *>(val)); 213 break; 214 default: visitor->Unknown(val); 215 } 216 } else { 217 visitor->Unknown(val); 218 } 219 break; 220 } 221 case ST_ENUM: FLATBUFFERS_ASSERT(false); break; 222 } 223 break; 224 } 225 default: { 226 visitor->Unknown(val); 227 break; 228 } 229 } 230 } 231 232 inline void IterateObject(const uint8_t *obj, const TypeTable *type_table, 233 IterationVisitor *visitor) { 234 visitor->StartSequence(); 235 const uint8_t *prev_val = nullptr; 236 size_t set_idx = 0; 237 size_t array_idx = 0; 238 for (size_t i = 0; i < type_table->num_elems; i++) { 239 auto type_code = type_table->type_codes[i]; 240 auto type = static_cast<ElementaryType>(type_code.base_type); 241 auto is_repeating = type_code.is_repeating != 0; 242 auto ref_idx = type_code.sequence_ref; 243 const TypeTable *ref = nullptr; 244 if (ref_idx >= 0) { ref = type_table->type_refs[ref_idx](); } 245 auto name = type_table->names ? type_table->names[i] : nullptr; 246 const uint8_t *val = nullptr; 247 if (type_table->st == ST_TABLE) { 248 val = reinterpret_cast<const Table *>(obj)->GetAddressOf( 249 FieldIndexToOffset(static_cast<voffset_t>(i))); 250 } else { 251 val = obj + type_table->values[i]; 252 } 253 visitor->Field(i, set_idx, type, is_repeating, ref, name, val); 254 if (val) { 255 set_idx++; 256 if (is_repeating) { 257 auto elem_ptr = val; 258 size_t size = 0; 259 if (type_table->st == ST_TABLE) { 260 // variable length vector 261 val += ReadScalar<uoffset_t>(val); 262 auto vec = reinterpret_cast<const Vector<uint8_t> *>(val); 263 elem_ptr = vec->Data(); 264 size = vec->size(); 265 } else { 266 // otherwise fixed size array 267 size = type_table->array_sizes[array_idx]; 268 ++array_idx; 269 } 270 visitor->StartVector(); 271 for (size_t j = 0; j < size; j++) { 272 visitor->Element(j, type, ref, elem_ptr); 273 IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j), 274 visitor); 275 elem_ptr += InlineSize(type, ref); 276 } 277 visitor->EndVector(); 278 } else { 279 IterateValue(type, val, ref, prev_val, -1, visitor); 280 } 281 } 282 prev_val = val; 283 } 284 visitor->EndSequence(); 285 } 286 287 inline void IterateFlatBuffer(const uint8_t *buffer, 288 const TypeTable *type_table, 289 IterationVisitor *callback) { 290 IterateObject(GetRoot<uint8_t>(buffer), type_table, callback); 291 } 292 293 // Outputting a Flatbuffer to a string. Tries to conform as close to JSON / 294 // the output generated by idl_gen_text.cpp. 295 296 struct ToStringVisitor : public IterationVisitor { 297 std::string s; 298 std::string d; 299 bool q; 300 std::string in; 301 size_t indent_level; 302 bool vector_delimited; 303 ToStringVisitor(std::string delimiter, bool quotes, std::string indent, 304 bool vdelimited = true) 305 : d(delimiter), 306 q(quotes), 307 in(indent), 308 indent_level(0), 309 vector_delimited(vdelimited) {} 310 ToStringVisitor(std::string delimiter) 311 : d(delimiter), 312 q(false), 313 in(""), 314 indent_level(0), 315 vector_delimited(true) {} 316 317 void append_indent() { 318 for (size_t i = 0; i < indent_level; i++) { s += in; } 319 } 320 321 void StartSequence() { 322 s += "{"; 323 s += d; 324 indent_level++; 325 } 326 void EndSequence() { 327 s += d; 328 indent_level--; 329 append_indent(); 330 s += "}"; 331 } 332 void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/, 333 bool /*is_vector*/, const TypeTable * /*type_table*/, 334 const char *name, const uint8_t *val) { 335 if (!val) return; 336 if (set_idx) { 337 s += ","; 338 s += d; 339 } 340 append_indent(); 341 if (name) { 342 if (q) s += "\""; 343 s += name; 344 if (q) s += "\""; 345 s += ": "; 346 } 347 } 348 template<typename T> void Named(T x, const char *name) { 349 if (name) { 350 if (q) s += "\""; 351 s += name; 352 if (q) s += "\""; 353 } else { 354 s += NumToString(x); 355 } 356 } 357 void UType(uint8_t x, const char *name) { Named(x, name); } 358 void Bool(bool x) { s += x ? "true" : "false"; } 359 void Char(int8_t x, const char *name) { Named(x, name); } 360 void UChar(uint8_t x, const char *name) { Named(x, name); } 361 void Short(int16_t x, const char *name) { Named(x, name); } 362 void UShort(uint16_t x, const char *name) { Named(x, name); } 363 void Int(int32_t x, const char *name) { Named(x, name); } 364 void UInt(uint32_t x, const char *name) { Named(x, name); } 365 void Long(int64_t x) { s += NumToString(x); } 366 void ULong(uint64_t x) { s += NumToString(x); } 367 void Float(float x) { s += NumToString(x); } 368 void Double(double x) { s += NumToString(x); } 369 void String(const struct String *str) { 370 EscapeString(str->c_str(), str->size(), &s, true, false); 371 } 372 void Unknown(const uint8_t *) { s += "(?)"; } 373 void StartVector() { 374 s += "["; 375 if (vector_delimited) { 376 s += d; 377 indent_level++; 378 append_indent(); 379 } else { 380 s += " "; 381 } 382 } 383 void EndVector() { 384 if (vector_delimited) { 385 s += d; 386 indent_level--; 387 append_indent(); 388 } else { 389 s += " "; 390 } 391 s += "]"; 392 } 393 void Element(size_t i, ElementaryType /*type*/, 394 const TypeTable * /*type_table*/, const uint8_t * /*val*/) { 395 if (i) { 396 s += ","; 397 if (vector_delimited) { 398 s += d; 399 append_indent(); 400 } else { 401 s += " "; 402 } 403 } 404 } 405 }; 406 407 inline std::string FlatBufferToString(const uint8_t *buffer, 408 const TypeTable *type_table, 409 bool multi_line = false, 410 bool vector_delimited = true) { 411 ToStringVisitor tostring_visitor(multi_line ? "\n" : " ", false, "", 412 vector_delimited); 413 IterateFlatBuffer(buffer, type_table, &tostring_visitor); 414 return tostring_visitor.s; 415 } 416 417 } // namespace flatbuffers 418 419 #endif // FLATBUFFERS_MINIREFLECT_H_