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_