Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright 2015 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 #include "flatbuffers/reflection.h"
     18 #include "flatbuffers/util.h"
     19 
     20 // Helper functionality for reflection.
     21 
     22 namespace flatbuffers {
     23 
     24 int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
     25   // clang-format off
     26   #define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
     27   switch (type) {
     28     case reflection::UType:
     29     case reflection::Bool:
     30     case reflection::UByte:  return FLATBUFFERS_GET(uint8_t);
     31     case reflection::Byte:   return FLATBUFFERS_GET(int8_t);
     32     case reflection::Short:  return FLATBUFFERS_GET(int16_t);
     33     case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
     34     case reflection::Int:    return FLATBUFFERS_GET(int32_t);
     35     case reflection::UInt:   return FLATBUFFERS_GET(uint32_t);
     36     case reflection::Long:   return FLATBUFFERS_GET(int64_t);
     37     case reflection::ULong:  return FLATBUFFERS_GET(uint64_t);
     38     case reflection::Float:  return FLATBUFFERS_GET(float);
     39     case reflection::Double: return FLATBUFFERS_GET(double);
     40     case reflection::String: {
     41       auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
     42                                                 data);
     43       return s ? StringToInt(s->c_str()) : 0;
     44     }
     45     default: return 0;  // Tables & vectors do not make sense.
     46   }
     47   #undef FLATBUFFERS_GET
     48   // clang-format on
     49 }
     50 
     51 double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
     52   switch (type) {
     53     case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
     54     case reflection::Double: return ReadScalar<double>(data);
     55     case reflection::String: {
     56       auto s =
     57           reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
     58       return s ? strtod(s->c_str(), nullptr) : 0.0;
     59     }
     60     default: return static_cast<double>(GetAnyValueI(type, data));
     61   }
     62 }
     63 
     64 std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
     65                          const reflection::Schema *schema, int type_index) {
     66   switch (type) {
     67     case reflection::Float:
     68     case reflection::Double: return NumToString(GetAnyValueF(type, data));
     69     case reflection::String: {
     70       auto s =
     71           reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
     72       return s ? s->c_str() : "";
     73     }
     74     case reflection::Obj:
     75       if (schema) {
     76         // Convert the table to a string. This is mostly for debugging purposes,
     77         // and does NOT promise to be JSON compliant.
     78         // Also prefixes the type.
     79         auto &objectdef = *schema->objects()->Get(type_index);
     80         auto s = objectdef.name()->str();
     81         if (objectdef.is_struct()) {
     82           s += "(struct)";  // TODO: implement this as well.
     83         } else {
     84           auto table_field = reinterpret_cast<const Table *>(
     85               ReadScalar<uoffset_t>(data) + data);
     86           s += " { ";
     87           auto fielddefs = objectdef.fields();
     88           for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
     89             auto &fielddef = **it;
     90             if (!table_field->CheckField(fielddef.offset())) continue;
     91             auto val = GetAnyFieldS(*table_field, fielddef, schema);
     92             if (fielddef.type()->base_type() == reflection::String) {
     93               std::string esc;
     94               flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true,
     95                                         false);
     96               val = esc;
     97             }
     98             s += fielddef.name()->str();
     99             s += ": ";
    100             s += val;
    101             s += ", ";
    102           }
    103           s += "}";
    104         }
    105         return s;
    106       } else {
    107         return "(table)";
    108       }
    109     case reflection::Vector:
    110       return "[(elements)]";                   // TODO: implement this as well.
    111     case reflection::Union: return "(union)";  // TODO: implement this as well.
    112     default: return NumToString(GetAnyValueI(type, data));
    113   }
    114 }
    115 
    116 void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
    117   // clang-format off
    118   #define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
    119   switch (type) {
    120     case reflection::UType:
    121     case reflection::Bool:
    122     case reflection::UByte:  FLATBUFFERS_SET(uint8_t ); break;
    123     case reflection::Byte:   FLATBUFFERS_SET(int8_t  ); break;
    124     case reflection::Short:  FLATBUFFERS_SET(int16_t ); break;
    125     case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
    126     case reflection::Int:    FLATBUFFERS_SET(int32_t ); break;
    127     case reflection::UInt:   FLATBUFFERS_SET(uint32_t); break;
    128     case reflection::Long:   FLATBUFFERS_SET(int64_t ); break;
    129     case reflection::ULong:  FLATBUFFERS_SET(uint64_t); break;
    130     case reflection::Float:  FLATBUFFERS_SET(float   ); break;
    131     case reflection::Double: FLATBUFFERS_SET(double  ); break;
    132     // TODO: support strings
    133     default: break;
    134   }
    135   #undef FLATBUFFERS_SET
    136   // clang-format on
    137 }
    138 
    139 void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
    140   switch (type) {
    141     case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
    142     case reflection::Double: WriteScalar(data, val); break;
    143     // TODO: support strings.
    144     default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
    145   }
    146 }
    147 
    148 void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
    149   switch (type) {
    150     case reflection::Float:
    151     case reflection::Double:
    152       SetAnyValueF(type, data, strtod(val, nullptr));
    153       break;
    154     // TODO: support strings.
    155     default: SetAnyValueI(type, data, StringToInt(val)); break;
    156   }
    157 }
    158 
    159 // Resize a FlatBuffer in-place by iterating through all offsets in the buffer
    160 // and adjusting them by "delta" if they straddle the start offset.
    161 // Once that is done, bytes can now be inserted/deleted safely.
    162 // "delta" may be negative (shrinking).
    163 // Unless "delta" is a multiple of the largest alignment, you'll create a small
    164 // amount of garbage space in the buffer (usually 0..7 bytes).
    165 // If your FlatBuffer's root table is not the schema's root table, you should
    166 // pass in your root_table type as well.
    167 class ResizeContext {
    168  public:
    169   ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
    170                 std::vector<uint8_t> *flatbuf,
    171                 const reflection::Object *root_table = nullptr)
    172       : schema_(schema),
    173         startptr_(vector_data(*flatbuf) + start),
    174         delta_(delta),
    175         buf_(*flatbuf),
    176         dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
    177     auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
    178     delta_ = (delta_ + mask) & ~mask;
    179     if (!delta_) return;  // We can't shrink by less than largest_scalar_t.
    180     // Now change all the offsets by delta_.
    181     auto root = GetAnyRoot(vector_data(buf_));
    182     Straddle<uoffset_t, 1>(vector_data(buf_), root, vector_data(buf_));
    183     ResizeTable(root_table ? *root_table : *schema.root_table(), root);
    184     // We can now add or remove bytes at start.
    185     if (delta_ > 0)
    186       buf_.insert(buf_.begin() + start, delta_, 0);
    187     else
    188       buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
    189   }
    190 
    191   // Check if the range between first (lower address) and second straddles
    192   // the insertion point. If it does, change the offset at offsetloc (of
    193   // type T, with direction D).
    194   template<typename T, int D>
    195   void Straddle(const void *first, const void *second, void *offsetloc) {
    196     if (first <= startptr_ && second >= startptr_) {
    197       WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
    198       DagCheck(offsetloc) = true;
    199     }
    200   }
    201 
    202   // This returns a boolean that records if the corresponding offset location
    203   // has been modified already. If so, we can't even read the corresponding
    204   // offset, since it is pointing to a location that is illegal until the
    205   // resize actually happens.
    206   // This must be checked for every offset, since we can't know which offsets
    207   // will straddle and which won't.
    208   uint8_t &DagCheck(const void *offsetloc) {
    209     auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
    210                    reinterpret_cast<const uoffset_t *>(vector_data(buf_));
    211     return dag_check_[dag_idx];
    212   }
    213 
    214   void ResizeTable(const reflection::Object &objectdef, Table *table) {
    215     if (DagCheck(table)) return;  // Table already visited.
    216     auto vtable = table->GetVTable();
    217     // Early out: since all fields inside the table must point forwards in
    218     // memory, if the insertion point is before the table we can stop here.
    219     auto tableloc = reinterpret_cast<uint8_t *>(table);
    220     if (startptr_ <= tableloc) {
    221       // Check if insertion point is between the table and a vtable that
    222       // precedes it. This can't happen in current construction code, but check
    223       // just in case we ever change the way flatbuffers are built.
    224       Straddle<soffset_t, -1>(vtable, table, table);
    225     } else {
    226       // Check each field.
    227       auto fielddefs = objectdef.fields();
    228       for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
    229         auto &fielddef = **it;
    230         auto base_type = fielddef.type()->base_type();
    231         // Ignore scalars.
    232         if (base_type <= reflection::Double) continue;
    233         // Ignore fields that are not stored.
    234         auto offset = table->GetOptionalFieldOffset(fielddef.offset());
    235         if (!offset) continue;
    236         // Ignore structs.
    237         auto subobjectdef =
    238             base_type == reflection::Obj
    239                 ? schema_.objects()->Get(fielddef.type()->index())
    240                 : nullptr;
    241         if (subobjectdef && subobjectdef->is_struct()) continue;
    242         // Get this fields' offset, and read it if safe.
    243         auto offsetloc = tableloc + offset;
    244         if (DagCheck(offsetloc)) continue;  // This offset already visited.
    245         auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
    246         Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
    247         // Recurse.
    248         switch (base_type) {
    249           case reflection::Obj: {
    250             ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
    251             break;
    252           }
    253           case reflection::Vector: {
    254             auto elem_type = fielddef.type()->element();
    255             if (elem_type != reflection::Obj && elem_type != reflection::String)
    256               break;
    257             auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
    258             auto elemobjectdef =
    259                 elem_type == reflection::Obj
    260                     ? schema_.objects()->Get(fielddef.type()->index())
    261                     : nullptr;
    262             if (elemobjectdef && elemobjectdef->is_struct()) break;
    263             for (uoffset_t i = 0; i < vec->size(); i++) {
    264               auto loc = vec->Data() + i * sizeof(uoffset_t);
    265               if (DagCheck(loc)) continue;  // This offset already visited.
    266               auto dest = loc + vec->Get(i);
    267               Straddle<uoffset_t, 1>(loc, dest, loc);
    268               if (elemobjectdef)
    269                 ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
    270             }
    271             break;
    272           }
    273           case reflection::Union: {
    274             ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
    275                         reinterpret_cast<Table *>(ref));
    276             break;
    277           }
    278           case reflection::String: break;
    279           default: FLATBUFFERS_ASSERT(false);
    280         }
    281       }
    282       // Check if the vtable offset points beyond the insertion point.
    283       // Must do this last, since GetOptionalFieldOffset above still reads
    284       // this value.
    285       Straddle<soffset_t, -1>(table, vtable, table);
    286     }
    287   }
    288 
    289   void operator=(const ResizeContext &rc);
    290 
    291  private:
    292   const reflection::Schema &schema_;
    293   uint8_t *startptr_;
    294   int delta_;
    295   std::vector<uint8_t> &buf_;
    296   std::vector<uint8_t> dag_check_;
    297 };
    298 
    299 void SetString(const reflection::Schema &schema, const std::string &val,
    300                const String *str, std::vector<uint8_t> *flatbuf,
    301                const reflection::Object *root_table) {
    302   auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size());
    303   auto str_start = static_cast<uoffset_t>(
    304       reinterpret_cast<const uint8_t *>(str) - vector_data(*flatbuf));
    305   auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t));
    306   if (delta) {
    307     // Clear the old string, since we don't want parts of it remaining.
    308     memset(vector_data(*flatbuf) + start, 0, str->size());
    309     // Different size, we must expand (or contract).
    310     ResizeContext(schema, start, delta, flatbuf, root_table);
    311     // Set the new length.
    312     WriteScalar(vector_data(*flatbuf) + str_start,
    313                 static_cast<uoffset_t>(val.size()));
    314   }
    315   // Copy new data. Safe because we created the right amount of space.
    316   memcpy(vector_data(*flatbuf) + start, val.c_str(), val.size() + 1);
    317 }
    318 
    319 uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
    320                          const VectorOfAny *vec, uoffset_t num_elems,
    321                          uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
    322                          const reflection::Object *root_table) {
    323   auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
    324   auto delta_bytes = delta_elem * static_cast<int>(elem_size);
    325   auto vec_start =
    326       reinterpret_cast<const uint8_t *>(vec) - vector_data(*flatbuf);
    327   auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
    328                                       elem_size * num_elems);
    329   if (delta_bytes) {
    330     if (delta_elem < 0) {
    331       // Clear elements we're throwing away, since some might remain in the
    332       // buffer.
    333       auto size_clear = -delta_elem * elem_size;
    334       memset(vector_data(*flatbuf) + start - size_clear, 0, size_clear);
    335     }
    336     ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
    337     WriteScalar(vector_data(*flatbuf) + vec_start, newsize);  // Length field.
    338     // Set new elements to 0.. this can be overwritten by the caller.
    339     if (delta_elem > 0) {
    340       memset(vector_data(*flatbuf) + start, 0, delta_elem * elem_size);
    341     }
    342   }
    343   return vector_data(*flatbuf) + start;
    344 }
    345 
    346 const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
    347                              const uint8_t *newbuf, size_t newlen) {
    348   // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
    349   // going to chop off the root offset.
    350   while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
    351          !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
    352     flatbuf.push_back(0);
    353   }
    354   auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
    355   // Insert the entire FlatBuffer minus the root pointer.
    356   flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
    357   auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
    358   return vector_data(flatbuf) + insertion_point + root_offset;
    359 }
    360 
    361 void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
    362                 const Table &table, size_t align, size_t size) {
    363   fbb.Align(align);
    364   fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
    365   fbb.TrackField(fielddef.offset(), fbb.GetSize());
    366 }
    367 
    368 Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
    369                                 const reflection::Schema &schema,
    370                                 const reflection::Object &objectdef,
    371                                 const Table &table, bool use_string_pooling) {
    372   // Before we can construct the table, we have to first generate any
    373   // subobjects, and collect their offsets.
    374   std::vector<uoffset_t> offsets;
    375   auto fielddefs = objectdef.fields();
    376   for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
    377     auto &fielddef = **it;
    378     // Skip if field is not present in the source.
    379     if (!table.CheckField(fielddef.offset())) continue;
    380     uoffset_t offset = 0;
    381     switch (fielddef.type()->base_type()) {
    382       case reflection::String: {
    383         offset = use_string_pooling
    384                      ? fbb.CreateSharedString(GetFieldS(table, fielddef)).o
    385                      : fbb.CreateString(GetFieldS(table, fielddef)).o;
    386         break;
    387       }
    388       case reflection::Obj: {
    389         auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
    390         if (!subobjectdef.is_struct()) {
    391           offset =
    392               CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef))
    393                   .o;
    394         }
    395         break;
    396       }
    397       case reflection::Union: {
    398         auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
    399         offset =
    400             CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef)).o;
    401         break;
    402       }
    403       case reflection::Vector: {
    404         auto vec =
    405             table.GetPointer<const Vector<Offset<Table>> *>(fielddef.offset());
    406         auto element_base_type = fielddef.type()->element();
    407         auto elemobjectdef =
    408             element_base_type == reflection::Obj
    409                 ? schema.objects()->Get(fielddef.type()->index())
    410                 : nullptr;
    411         switch (element_base_type) {
    412           case reflection::String: {
    413             std::vector<Offset<const String *>> elements(vec->size());
    414             auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
    415             for (uoffset_t i = 0; i < vec_s->size(); i++) {
    416               elements[i] = use_string_pooling
    417                                 ? fbb.CreateSharedString(vec_s->Get(i)).o
    418                                 : fbb.CreateString(vec_s->Get(i)).o;
    419             }
    420             offset = fbb.CreateVector(elements).o;
    421             break;
    422           }
    423           case reflection::Obj: {
    424             if (!elemobjectdef->is_struct()) {
    425               std::vector<Offset<const Table *>> elements(vec->size());
    426               for (uoffset_t i = 0; i < vec->size(); i++) {
    427                 elements[i] =
    428                     CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
    429               }
    430               offset = fbb.CreateVector(elements).o;
    431               break;
    432             }
    433           }
    434           FLATBUFFERS_FALLTHROUGH(); // fall thru
    435           default: {  // Scalars and structs.
    436             auto element_size = GetTypeSize(element_base_type);
    437             if (elemobjectdef && elemobjectdef->is_struct())
    438               element_size = elemobjectdef->bytesize();
    439             fbb.StartVector(vec->size(), element_size);
    440             fbb.PushBytes(vec->Data(), element_size * vec->size());
    441             offset = fbb.EndVector(vec->size());
    442             break;
    443           }
    444         }
    445         break;
    446       }
    447       default:  // Scalars.
    448         break;
    449     }
    450     if (offset) { offsets.push_back(offset); }
    451   }
    452   // Now we can build the actual table from either offsets or scalar data.
    453   auto start = objectdef.is_struct() ? fbb.StartStruct(objectdef.minalign())
    454                                      : fbb.StartTable();
    455   size_t offset_idx = 0;
    456   for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
    457     auto &fielddef = **it;
    458     if (!table.CheckField(fielddef.offset())) continue;
    459     auto base_type = fielddef.type()->base_type();
    460     switch (base_type) {
    461       case reflection::Obj: {
    462         auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
    463         if (subobjectdef.is_struct()) {
    464           CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
    465                      subobjectdef.bytesize());
    466           break;
    467         }
    468       }
    469       FLATBUFFERS_FALLTHROUGH(); // fall thru
    470       case reflection::Union:
    471       case reflection::String:
    472       case reflection::Vector:
    473         fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
    474         break;
    475       default: {  // Scalars.
    476         auto size = GetTypeSize(base_type);
    477         CopyInline(fbb, fielddef, table, size, size);
    478         break;
    479       }
    480     }
    481   }
    482   FLATBUFFERS_ASSERT(offset_idx == offsets.size());
    483   if (objectdef.is_struct()) {
    484     fbb.ClearOffsets();
    485     return fbb.EndStruct();
    486   } else {
    487     return fbb.EndTable(start);
    488   }
    489 }
    490 
    491 bool VerifyStruct(flatbuffers::Verifier &v,
    492                   const flatbuffers::Table &parent_table,
    493                   voffset_t field_offset, const reflection::Object &obj,
    494                   bool required) {
    495   auto offset = parent_table.GetOptionalFieldOffset(field_offset);
    496   if (required && !offset) { return false; }
    497 
    498   return !offset ||
    499          v.Verify(reinterpret_cast<const uint8_t *>(&parent_table), offset,
    500                   obj.bytesize());
    501 }
    502 
    503 bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
    504                            const flatbuffers::Table &parent_table,
    505                            voffset_t field_offset,
    506                            const reflection::Object &obj, bool required) {
    507   auto p = parent_table.GetPointer<const uint8_t *>(field_offset);
    508   if (required && !p) { return false; }
    509 
    510   return !p || v.VerifyVectorOrString(p, obj.bytesize());
    511 }
    512 
    513 // forward declare to resolve cyclic deps between VerifyObject and VerifyVector
    514 bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
    515                   const reflection::Object &obj,
    516                   const flatbuffers::Table *table, bool required);
    517 
    518 bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
    519                   const flatbuffers::Table &table,
    520                   const reflection::Field &vec_field) {
    521   FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector);
    522   if (!table.VerifyField<uoffset_t>(v, vec_field.offset())) return false;
    523 
    524   switch (vec_field.type()->element()) {
    525     case reflection::None: FLATBUFFERS_ASSERT(false); break;
    526     case reflection::UType:
    527       return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
    528     case reflection::Bool:
    529     case reflection::Byte:
    530     case reflection::UByte:
    531       return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field));
    532     case reflection::Short:
    533     case reflection::UShort:
    534       return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field));
    535     case reflection::Int:
    536     case reflection::UInt:
    537       return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field));
    538     case reflection::Long:
    539     case reflection::ULong:
    540       return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field));
    541     case reflection::Float:
    542       return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field));
    543     case reflection::Double:
    544       return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field));
    545     case reflection::String: {
    546       auto vec_string =
    547           flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
    548               table, vec_field);
    549       if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) {
    550         return true;
    551       } else {
    552         return false;
    553       }
    554     }
    555     case reflection::Vector: FLATBUFFERS_ASSERT(false); break;
    556     case reflection::Obj: {
    557       auto obj = schema.objects()->Get(vec_field.type()->index());
    558       if (obj->is_struct()) {
    559         if (!VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
    560                                    vec_field.required())) {
    561           return false;
    562         }
    563       } else {
    564         auto vec =
    565             flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>(
    566                 table, vec_field);
    567         if (!v.VerifyVector(vec)) return false;
    568         if (vec) {
    569           for (uoffset_t j = 0; j < vec->size(); j++) {
    570             if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
    571               return false;
    572             }
    573           }
    574         }
    575       }
    576       return true;
    577     }
    578     case reflection::Union: FLATBUFFERS_ASSERT(false); break;
    579     default: FLATBUFFERS_ASSERT(false); break;
    580   }
    581 
    582   return false;
    583 }
    584 
    585 bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
    586                   const reflection::Object &obj,
    587                   const flatbuffers::Table *table, bool required) {
    588   if (!table) {
    589     if (!required)
    590       return true;
    591     else
    592       return false;
    593   }
    594 
    595   if (!table->VerifyTableStart(v)) return false;
    596 
    597   for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
    598     auto field_def = obj.fields()->Get(i);
    599     switch (field_def->type()->base_type()) {
    600       case reflection::None: FLATBUFFERS_ASSERT(false); break;
    601       case reflection::UType:
    602         if (!table->VerifyField<uint8_t>(v, field_def->offset())) return false;
    603         break;
    604       case reflection::Bool:
    605       case reflection::Byte:
    606       case reflection::UByte:
    607         if (!table->VerifyField<int8_t>(v, field_def->offset())) return false;
    608         break;
    609       case reflection::Short:
    610       case reflection::UShort:
    611         if (!table->VerifyField<int16_t>(v, field_def->offset())) return false;
    612         break;
    613       case reflection::Int:
    614       case reflection::UInt:
    615         if (!table->VerifyField<int32_t>(v, field_def->offset())) return false;
    616         break;
    617       case reflection::Long:
    618       case reflection::ULong:
    619         if (!table->VerifyField<int64_t>(v, field_def->offset())) return false;
    620         break;
    621       case reflection::Float:
    622         if (!table->VerifyField<float>(v, field_def->offset())) return false;
    623         break;
    624       case reflection::Double:
    625         if (!table->VerifyField<double>(v, field_def->offset())) return false;
    626         break;
    627       case reflection::String:
    628         if (!table->VerifyField<uoffset_t>(v, field_def->offset()) ||
    629             !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) {
    630           return false;
    631         }
    632         break;
    633       case reflection::Vector:
    634         if (!VerifyVector(v, schema, *table, *field_def)) return false;
    635         break;
    636       case reflection::Obj: {
    637         auto child_obj = schema.objects()->Get(field_def->type()->index());
    638         if (child_obj->is_struct()) {
    639           if (!VerifyStruct(v, *table, field_def->offset(), *child_obj,
    640                             field_def->required())) {
    641             return false;
    642           }
    643         } else {
    644           if (!VerifyObject(v, schema, *child_obj,
    645                             flatbuffers::GetFieldT(*table, *field_def),
    646                             field_def->required())) {
    647             return false;
    648           }
    649         }
    650         break;
    651       }
    652       case reflection::Union: {
    653         //  get union type from the prev field
    654         voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
    655         auto utype = table->GetField<uint8_t>(utype_offset, 0);
    656         if (utype != 0) {
    657           // Means we have this union field present
    658           auto fb_enum = schema.enums()->Get(field_def->type()->index());
    659           auto child_obj = fb_enum->values()->Get(utype)->object();
    660           if (!VerifyObject(v, schema, *child_obj,
    661                             flatbuffers::GetFieldT(*table, *field_def),
    662                             field_def->required())) {
    663             return false;
    664           }
    665         }
    666         break;
    667       }
    668       default: FLATBUFFERS_ASSERT(false); break;
    669     }
    670   }
    671 
    672   if (!v.EndTable()) return false;
    673 
    674   return true;
    675 }
    676 
    677 bool Verify(const reflection::Schema &schema, const reflection::Object &root,
    678             const uint8_t *buf, size_t length) {
    679   Verifier v(buf, length);
    680   return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), true);
    681 }
    682 
    683 }  // namespace flatbuffers
    684