| /* |
| * Copyright 2015 Google Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "flatbuffers/reflection.h" |
| |
| #include "flatbuffers/util.h" |
| |
| // Helper functionality for reflection. |
| |
| namespace flatbuffers { |
| |
| namespace { |
| |
| static void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef, |
| const Table &table, size_t align, size_t size) { |
| fbb.Align(align); |
| fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size); |
| fbb.TrackField(fielddef.offset(), fbb.GetSize()); |
| } |
| |
| static bool VerifyStruct(flatbuffers::Verifier &v, |
| const flatbuffers::Table &parent_table, |
| voffset_t field_offset, const reflection::Object &obj, |
| bool required) { |
| auto offset = parent_table.GetOptionalFieldOffset(field_offset); |
| if (required && !offset) { return false; } |
| |
| return !offset || |
| v.VerifyFieldStruct(reinterpret_cast<const uint8_t *>(&parent_table), |
| offset, obj.bytesize(), obj.minalign()); |
| } |
| |
| static bool VerifyVectorOfStructs(flatbuffers::Verifier &v, |
| const flatbuffers::Table &parent_table, |
| voffset_t field_offset, |
| const reflection::Object &obj, bool required) { |
| auto p = parent_table.GetPointer<const uint8_t *>(field_offset); |
| if (required && !p) { return false; } |
| |
| return !p || v.VerifyVectorOrString(p, obj.bytesize()); |
| } |
| |
| // forward declare to resolve cyclic deps between VerifyObject and VerifyVector |
| static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, |
| const reflection::Object &obj, |
| const flatbuffers::Table *table, bool required); |
| |
| static bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema, |
| uint8_t utype, const uint8_t *elem, |
| const reflection::Field &union_field) { |
| if (!utype) return true; // Not present. |
| auto fb_enum = schema.enums()->Get(union_field.type()->index()); |
| if (utype >= fb_enum->values()->size()) return false; |
| auto elem_type = fb_enum->values()->Get(utype)->union_type(); |
| switch (elem_type->base_type()) { |
| case reflection::Obj: { |
| auto elem_obj = schema.objects()->Get(elem_type->index()); |
| if (elem_obj->is_struct()) { |
| return v.VerifyFromPointer(elem, elem_obj->bytesize()); |
| } else { |
| return VerifyObject(v, schema, *elem_obj, |
| reinterpret_cast<const flatbuffers::Table *>(elem), |
| true); |
| } |
| } |
| case reflection::String: |
| return v.VerifyString( |
| reinterpret_cast<const flatbuffers::String *>(elem)); |
| default: return false; |
| } |
| } |
| |
| static bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema, |
| const flatbuffers::Table &table, |
| const reflection::Field &vec_field) { |
| FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector); |
| if (!table.VerifyField<uoffset_t>(v, vec_field.offset(), sizeof(uoffset_t))) |
| return false; |
| |
| switch (vec_field.type()->element()) { |
| case reflection::UType: |
| return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field)); |
| case reflection::Bool: |
| case reflection::Byte: |
| case reflection::UByte: |
| return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field)); |
| case reflection::Short: |
| case reflection::UShort: |
| return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field)); |
| case reflection::Int: |
| case reflection::UInt: |
| return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field)); |
| case reflection::Long: |
| case reflection::ULong: |
| return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field)); |
| case reflection::Float: |
| return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field)); |
| case reflection::Double: |
| return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field)); |
| case reflection::String: { |
| auto vec_string = |
| flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>( |
| table, vec_field); |
| if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| case reflection::Obj: { |
| auto obj = schema.objects()->Get(vec_field.type()->index()); |
| if (obj->is_struct()) { |
| return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj, |
| vec_field.required()); |
| } else { |
| auto vec = |
| flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>( |
| table, vec_field); |
| if (!v.VerifyVector(vec)) return false; |
| if (!vec) return true; |
| for (uoffset_t j = 0; j < vec->size(); j++) { |
| if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| } |
| case reflection::Union: { |
| auto vec = flatbuffers::GetFieldV<flatbuffers::Offset<uint8_t>>( |
| table, vec_field); |
| if (!v.VerifyVector(vec)) return false; |
| if (!vec) return true; |
| auto type_vec = table.GetPointer<Vector<uint8_t> *>(vec_field.offset() - |
| sizeof(voffset_t)); |
| if (!v.VerifyVector(type_vec)) return false; |
| for (uoffset_t j = 0; j < vec->size(); j++) { |
| // get union type from the prev field |
| auto utype = type_vec->Get(j); |
| auto elem = vec->Get(j); |
| if (!VerifyUnion(v, schema, utype, elem, vec_field)) return false; |
| } |
| return true; |
| } |
| case reflection::Vector: |
| case reflection::None: |
| default: FLATBUFFERS_ASSERT(false); return false; |
| } |
| } |
| |
| static bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, |
| const reflection::Object &obj, |
| const flatbuffers::Table *table, bool required) { |
| if (!table) return !required; |
| if (!table->VerifyTableStart(v)) return false; |
| for (uoffset_t i = 0; i < obj.fields()->size(); i++) { |
| auto field_def = obj.fields()->Get(i); |
| switch (field_def->type()->base_type()) { |
| case reflection::None: FLATBUFFERS_ASSERT(false); break; |
| case reflection::UType: |
| if (!table->VerifyField<uint8_t>(v, field_def->offset(), |
| sizeof(uint8_t))) |
| return false; |
| break; |
| case reflection::Bool: |
| case reflection::Byte: |
| case reflection::UByte: |
| if (!table->VerifyField<int8_t>(v, field_def->offset(), sizeof(int8_t))) |
| return false; |
| break; |
| case reflection::Short: |
| case reflection::UShort: |
| if (!table->VerifyField<int16_t>(v, field_def->offset(), |
| sizeof(int16_t))) |
| return false; |
| break; |
| case reflection::Int: |
| case reflection::UInt: |
| if (!table->VerifyField<int32_t>(v, field_def->offset(), |
| sizeof(int32_t))) |
| return false; |
| break; |
| case reflection::Long: |
| case reflection::ULong: |
| if (!table->VerifyField<int64_t>(v, field_def->offset(), |
| sizeof(int64_t))) |
| return false; |
| break; |
| case reflection::Float: |
| if (!table->VerifyField<float>(v, field_def->offset(), sizeof(float))) |
| return false; |
| break; |
| case reflection::Double: |
| if (!table->VerifyField<double>(v, field_def->offset(), sizeof(double))) |
| return false; |
| break; |
| case reflection::String: |
| if (!table->VerifyField<uoffset_t>(v, field_def->offset(), |
| sizeof(uoffset_t)) || |
| !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) { |
| return false; |
| } |
| break; |
| case reflection::Vector: |
| if (!VerifyVector(v, schema, *table, *field_def)) return false; |
| break; |
| case reflection::Obj: { |
| auto child_obj = schema.objects()->Get(field_def->type()->index()); |
| if (child_obj->is_struct()) { |
| if (!VerifyStruct(v, *table, field_def->offset(), *child_obj, |
| field_def->required())) { |
| return false; |
| } |
| } else { |
| if (!VerifyObject(v, schema, *child_obj, |
| flatbuffers::GetFieldT(*table, *field_def), |
| field_def->required())) { |
| return false; |
| } |
| } |
| break; |
| } |
| case reflection::Union: { |
| // get union type from the prev field |
| voffset_t utype_offset = field_def->offset() - sizeof(voffset_t); |
| auto utype = table->GetField<uint8_t>(utype_offset, 0); |
| auto uval = reinterpret_cast<const uint8_t *>( |
| flatbuffers::GetFieldT(*table, *field_def)); |
| if (!VerifyUnion(v, schema, utype, uval, *field_def)) { return false; } |
| break; |
| } |
| default: FLATBUFFERS_ASSERT(false); break; |
| } |
| } |
| |
| if (!v.EndTable()) return false; |
| |
| return true; |
| } |
| |
| |
| } // namespace |
| |
| int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) { |
| // clang-format off |
| #define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data)) |
| switch (type) { |
| case reflection::UType: |
| case reflection::Bool: |
| case reflection::UByte: return FLATBUFFERS_GET(uint8_t); |
| case reflection::Byte: return FLATBUFFERS_GET(int8_t); |
| case reflection::Short: return FLATBUFFERS_GET(int16_t); |
| case reflection::UShort: return FLATBUFFERS_GET(uint16_t); |
| case reflection::Int: return FLATBUFFERS_GET(int32_t); |
| case reflection::UInt: return FLATBUFFERS_GET(uint32_t); |
| case reflection::Long: return FLATBUFFERS_GET(int64_t); |
| case reflection::ULong: return FLATBUFFERS_GET(uint64_t); |
| case reflection::Float: return FLATBUFFERS_GET(float); |
| case reflection::Double: return FLATBUFFERS_GET(double); |
| case reflection::String: { |
| auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + |
| data); |
| return s ? StringToInt(s->c_str()) : 0; |
| } |
| default: return 0; // Tables & vectors do not make sense. |
| } |
| #undef FLATBUFFERS_GET |
| // clang-format on |
| } |
| |
| double GetAnyValueF(reflection::BaseType type, const uint8_t *data) { |
| switch (type) { |
| case reflection::Float: return static_cast<double>(ReadScalar<float>(data)); |
| case reflection::Double: return ReadScalar<double>(data); |
| case reflection::String: { |
| auto s = |
| reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data); |
| if (s) { |
| double d; |
| StringToNumber(s->c_str(), &d); |
| return d; |
| } else { |
| return 0.0; |
| } |
| } |
| default: return static_cast<double>(GetAnyValueI(type, data)); |
| } |
| } |
| |
| std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data, |
| const reflection::Schema *schema, int type_index) { |
| switch (type) { |
| case reflection::Float: |
| case reflection::Double: return NumToString(GetAnyValueF(type, data)); |
| case reflection::String: { |
| auto s = |
| reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data); |
| return s ? s->c_str() : ""; |
| } |
| case reflection::Obj: |
| if (schema) { |
| // Convert the table to a string. This is mostly for debugging purposes, |
| // and does NOT promise to be JSON compliant. |
| // Also prefixes the type. |
| auto &objectdef = *schema->objects()->Get(type_index); |
| auto s = objectdef.name()->str(); |
| if (objectdef.is_struct()) { |
| s += "(struct)"; // TODO: implement this as well. |
| } else { |
| auto table_field = reinterpret_cast<const Table *>( |
| ReadScalar<uoffset_t>(data) + data); |
| s += " { "; |
| auto fielddefs = objectdef.fields(); |
| for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { |
| auto &fielddef = **it; |
| if (!table_field->CheckField(fielddef.offset())) continue; |
| auto val = GetAnyFieldS(*table_field, fielddef, schema); |
| if (fielddef.type()->base_type() == reflection::String) { |
| std::string esc; |
| flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true, |
| false); |
| val = esc; |
| } |
| s += fielddef.name()->str(); |
| s += ": "; |
| s += val; |
| s += ", "; |
| } |
| s += "}"; |
| } |
| return s; |
| } else { |
| return "(table)"; |
| } |
| case reflection::Vector: |
| return "[(elements)]"; // TODO: implement this as well. |
| case reflection::Union: return "(union)"; // TODO: implement this as well. |
| default: return NumToString(GetAnyValueI(type, data)); |
| } |
| } |
| |
| void ForAllFields(const reflection::Object *object, bool reverse, |
| std::function<void(const reflection::Field *)> func) { |
| std::vector<uint32_t> field_to_id_map; |
| field_to_id_map.resize(object->fields()->size()); |
| |
| // Create the mapping of field ID to the index into the vector. |
| for (uint32_t i = 0; i < object->fields()->size(); ++i) { |
| auto field = object->fields()->Get(i); |
| field_to_id_map[field->id()] = i; |
| } |
| |
| for (size_t i = 0; i < field_to_id_map.size(); ++i) { |
| func(object->fields()->Get( |
| field_to_id_map[reverse ? field_to_id_map.size() - i + 1 : i])); |
| } |
| } |
| |
| void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) { |
| // clang-format off |
| #define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val)) |
| switch (type) { |
| case reflection::UType: |
| case reflection::Bool: |
| case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break; |
| case reflection::Byte: FLATBUFFERS_SET(int8_t ); break; |
| case reflection::Short: FLATBUFFERS_SET(int16_t ); break; |
| case reflection::UShort: FLATBUFFERS_SET(uint16_t); break; |
| case reflection::Int: FLATBUFFERS_SET(int32_t ); break; |
| case reflection::UInt: FLATBUFFERS_SET(uint32_t); break; |
| case reflection::Long: FLATBUFFERS_SET(int64_t ); break; |
| case reflection::ULong: FLATBUFFERS_SET(uint64_t); break; |
| case reflection::Float: FLATBUFFERS_SET(float ); break; |
| case reflection::Double: FLATBUFFERS_SET(double ); break; |
| // TODO: support strings |
| default: break; |
| } |
| #undef FLATBUFFERS_SET |
| // clang-format on |
| } |
| |
| void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) { |
| switch (type) { |
| case reflection::Float: WriteScalar(data, static_cast<float>(val)); break; |
| case reflection::Double: WriteScalar(data, val); break; |
| // TODO: support strings. |
| default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break; |
| } |
| } |
| |
| void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) { |
| switch (type) { |
| case reflection::Float: |
| case reflection::Double: { |
| double d; |
| StringToNumber(val, &d); |
| SetAnyValueF(type, data, d); |
| break; |
| } |
| // TODO: support strings. |
| default: SetAnyValueI(type, data, StringToInt(val)); break; |
| } |
| } |
| |
| // Resize a FlatBuffer in-place by iterating through all offsets in the buffer |
| // and adjusting them by "delta" if they straddle the start offset. |
| // Once that is done, bytes can now be inserted/deleted safely. |
| // "delta" may be negative (shrinking). |
| // Unless "delta" is a multiple of the largest alignment, you'll create a small |
| // amount of garbage space in the buffer (usually 0..7 bytes). |
| // If your FlatBuffer's root table is not the schema's root table, you should |
| // pass in your root_table type as well. |
| class ResizeContext { |
| public: |
| ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta, |
| std::vector<uint8_t> *flatbuf, |
| const reflection::Object *root_table = nullptr) |
| : schema_(schema), |
| startptr_(flatbuf->data() + start), |
| delta_(delta), |
| buf_(*flatbuf), |
| dag_check_(flatbuf->size() / sizeof(uoffset_t), false) { |
| auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1); |
| delta_ = (delta_ + mask) & ~mask; |
| if (!delta_) return; // We can't shrink by less than largest_scalar_t. |
| // Now change all the offsets by delta_. |
| auto root = GetAnyRoot(buf_.data()); |
| Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data()); |
| ResizeTable(root_table ? *root_table : *schema.root_table(), root); |
| // We can now add or remove bytes at start. |
| if (delta_ > 0) |
| buf_.insert(buf_.begin() + start, delta_, 0); |
| else |
| buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start); |
| } |
| |
| // Check if the range between first (lower address) and second straddles |
| // the insertion point. If it does, change the offset at offsetloc (of |
| // type T, with direction D). |
| template<typename T, int D> |
| void Straddle(const void *first, const void *second, void *offsetloc) { |
| if (first <= startptr_ && second >= startptr_) { |
| WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D); |
| DagCheck(offsetloc) = true; |
| } |
| } |
| |
| // This returns a boolean that records if the corresponding offset location |
| // has been modified already. If so, we can't even read the corresponding |
| // offset, since it is pointing to a location that is illegal until the |
| // resize actually happens. |
| // This must be checked for every offset, since we can't know which offsets |
| // will straddle and which won't. |
| uint8_t &DagCheck(const void *offsetloc) { |
| auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) - |
| reinterpret_cast<const uoffset_t *>(buf_.data()); |
| return dag_check_[dag_idx]; |
| } |
| |
| void ResizeTable(const reflection::Object &objectdef, Table *table) { |
| if (DagCheck(table)) return; // Table already visited. |
| auto vtable = table->GetVTable(); |
| // Early out: since all fields inside the table must point forwards in |
| // memory, if the insertion point is before the table we can stop here. |
| auto tableloc = reinterpret_cast<uint8_t *>(table); |
| if (startptr_ <= tableloc) { |
| // Check if insertion point is between the table and a vtable that |
| // precedes it. This can't happen in current construction code, but check |
| // just in case we ever change the way flatbuffers are built. |
| Straddle<soffset_t, -1>(vtable, table, table); |
| } else { |
| // Check each field. |
| auto fielddefs = objectdef.fields(); |
| for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { |
| auto &fielddef = **it; |
| auto base_type = fielddef.type()->base_type(); |
| // Ignore scalars. |
| if (base_type <= reflection::Double) continue; |
| // Ignore fields that are not stored. |
| auto offset = table->GetOptionalFieldOffset(fielddef.offset()); |
| if (!offset) continue; |
| // Ignore structs. |
| auto subobjectdef = |
| base_type == reflection::Obj |
| ? schema_.objects()->Get(fielddef.type()->index()) |
| : nullptr; |
| if (subobjectdef && subobjectdef->is_struct()) continue; |
| // Get this fields' offset, and read it if safe. |
| auto offsetloc = tableloc + offset; |
| if (DagCheck(offsetloc)) continue; // This offset already visited. |
| auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc); |
| Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc); |
| // Recurse. |
| switch (base_type) { |
| case reflection::Obj: { |
| ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref)); |
| break; |
| } |
| case reflection::Vector: { |
| auto elem_type = fielddef.type()->element(); |
| if (elem_type != reflection::Obj && elem_type != reflection::String) |
| break; |
| auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref); |
| auto elemobjectdef = |
| elem_type == reflection::Obj |
| ? schema_.objects()->Get(fielddef.type()->index()) |
| : nullptr; |
| if (elemobjectdef && elemobjectdef->is_struct()) break; |
| for (uoffset_t i = 0; i < vec->size(); i++) { |
| auto loc = vec->Data() + i * sizeof(uoffset_t); |
| if (DagCheck(loc)) continue; // This offset already visited. |
| auto dest = loc + vec->Get(i); |
| Straddle<uoffset_t, 1>(loc, dest, loc); |
| if (elemobjectdef) |
| ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest)); |
| } |
| break; |
| } |
| case reflection::Union: { |
| ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table), |
| reinterpret_cast<Table *>(ref)); |
| break; |
| } |
| case reflection::String: break; |
| default: FLATBUFFERS_ASSERT(false); |
| } |
| } |
| // Check if the vtable offset points beyond the insertion point. |
| // Must do this last, since GetOptionalFieldOffset above still reads |
| // this value. |
| Straddle<soffset_t, -1>(table, vtable, table); |
| } |
| } |
| |
| private: |
| const reflection::Schema &schema_; |
| uint8_t *startptr_; |
| int delta_; |
| std::vector<uint8_t> &buf_; |
| std::vector<uint8_t> dag_check_; |
| }; |
| |
| void SetString(const reflection::Schema &schema, const std::string &val, |
| const String *str, std::vector<uint8_t> *flatbuf, |
| const reflection::Object *root_table) { |
| auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size()); |
| auto str_start = static_cast<uoffset_t>( |
| reinterpret_cast<const uint8_t *>(str) - flatbuf->data()); |
| auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t)); |
| if (delta) { |
| // Clear the old string, since we don't want parts of it remaining. |
| memset(flatbuf->data() + start, 0, str->size()); |
| // Different size, we must expand (or contract). |
| ResizeContext(schema, start, delta, flatbuf, root_table); |
| // Set the new length. |
| WriteScalar(flatbuf->data() + str_start, |
| static_cast<uoffset_t>(val.size())); |
| } |
| // Copy new data. Safe because we created the right amount of space. |
| memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1); |
| } |
| |
| uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize, |
| const VectorOfAny *vec, uoffset_t num_elems, |
| uoffset_t elem_size, std::vector<uint8_t> *flatbuf, |
| const reflection::Object *root_table) { |
| auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems); |
| auto delta_bytes = delta_elem * static_cast<int>(elem_size); |
| auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data(); |
| auto start = static_cast<uoffset_t>(vec_start) + |
| static_cast<uoffset_t>(sizeof(uoffset_t)) + |
| elem_size * num_elems; |
| if (delta_bytes) { |
| if (delta_elem < 0) { |
| // Clear elements we're throwing away, since some might remain in the |
| // buffer. |
| auto size_clear = -delta_elem * elem_size; |
| memset(flatbuf->data() + start - size_clear, 0, size_clear); |
| } |
| ResizeContext(schema, start, delta_bytes, flatbuf, root_table); |
| WriteScalar(flatbuf->data() + vec_start, newsize); // Length field. |
| // Set new elements to 0.. this can be overwritten by the caller. |
| if (delta_elem > 0) { |
| memset(flatbuf->data() + start, 0, |
| static_cast<size_t>(delta_elem) * elem_size); |
| } |
| } |
| return flatbuf->data() + start; |
| } |
| |
| const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf, |
| const uint8_t *newbuf, size_t newlen) { |
| // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're |
| // going to chop off the root offset. |
| while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) || |
| !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) { |
| flatbuf.push_back(0); |
| } |
| auto insertion_point = static_cast<uoffset_t>(flatbuf.size()); |
| // Insert the entire FlatBuffer minus the root pointer. |
| flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen); |
| auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t); |
| return flatbuf.data() + insertion_point + root_offset; |
| } |
| |
| |
| |
| |
| Offset<const Table *> CopyTable(FlatBufferBuilder &fbb, |
| const reflection::Schema &schema, |
| const reflection::Object &objectdef, |
| const Table &table, bool use_string_pooling) { |
| // Before we can construct the table, we have to first generate any |
| // subobjects, and collect their offsets. |
| std::vector<uoffset_t> offsets; |
| auto fielddefs = objectdef.fields(); |
| for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { |
| auto &fielddef = **it; |
| // Skip if field is not present in the source. |
| if (!table.CheckField(fielddef.offset())) continue; |
| uoffset_t offset = 0; |
| switch (fielddef.type()->base_type()) { |
| case reflection::String: { |
| offset = use_string_pooling |
| ? fbb.CreateSharedString(GetFieldS(table, fielddef)).o |
| : fbb.CreateString(GetFieldS(table, fielddef)).o; |
| break; |
| } |
| case reflection::Obj: { |
| auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index()); |
| if (!subobjectdef.is_struct()) { |
| offset = CopyTable(fbb, schema, subobjectdef, |
| *GetFieldT(table, fielddef), use_string_pooling) |
| .o; |
| } |
| break; |
| } |
| case reflection::Union: { |
| auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table); |
| offset = CopyTable(fbb, schema, subobjectdef, |
| *GetFieldT(table, fielddef), use_string_pooling) |
| .o; |
| break; |
| } |
| case reflection::Vector: { |
| auto vec = |
| table.GetPointer<const Vector<Offset<Table>> *>(fielddef.offset()); |
| auto element_base_type = fielddef.type()->element(); |
| auto elemobjectdef = |
| element_base_type == reflection::Obj |
| ? schema.objects()->Get(fielddef.type()->index()) |
| : nullptr; |
| switch (element_base_type) { |
| case reflection::String: { |
| std::vector<Offset<const String *>> elements(vec->size()); |
| auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec); |
| for (uoffset_t i = 0; i < vec_s->size(); i++) { |
| elements[i] = use_string_pooling |
| ? fbb.CreateSharedString(vec_s->Get(i)).o |
| : fbb.CreateString(vec_s->Get(i)).o; |
| } |
| offset = fbb.CreateVector(elements).o; |
| break; |
| } |
| case reflection::Obj: { |
| if (!elemobjectdef->is_struct()) { |
| std::vector<Offset<const Table *>> elements(vec->size()); |
| for (uoffset_t i = 0; i < vec->size(); i++) { |
| elements[i] = CopyTable(fbb, schema, *elemobjectdef, |
| *vec->Get(i), use_string_pooling); |
| } |
| offset = fbb.CreateVector(elements).o; |
| break; |
| } |
| } |
| FLATBUFFERS_FALLTHROUGH(); // fall thru |
| default: { // Scalars and structs. |
| auto element_size = GetTypeSize(element_base_type); |
| if (elemobjectdef && elemobjectdef->is_struct()) |
| element_size = elemobjectdef->bytesize(); |
| fbb.StartVector(vec->size(), element_size); |
| fbb.PushBytes(vec->Data(), element_size * vec->size()); |
| offset = fbb.EndVector(vec->size()); |
| break; |
| } |
| } |
| break; |
| } |
| default: // Scalars. |
| break; |
| } |
| if (offset) { offsets.push_back(offset); } |
| } |
| // Now we can build the actual table from either offsets or scalar data. |
| auto start = objectdef.is_struct() ? fbb.StartStruct(objectdef.minalign()) |
| : fbb.StartTable(); |
| size_t offset_idx = 0; |
| for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { |
| auto &fielddef = **it; |
| if (!table.CheckField(fielddef.offset())) continue; |
| auto base_type = fielddef.type()->base_type(); |
| switch (base_type) { |
| case reflection::Obj: { |
| auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index()); |
| if (subobjectdef.is_struct()) { |
| CopyInline(fbb, fielddef, table, subobjectdef.minalign(), |
| subobjectdef.bytesize()); |
| break; |
| } |
| } |
| FLATBUFFERS_FALLTHROUGH(); // fall thru |
| case reflection::Union: |
| case reflection::String: |
| case reflection::Vector: |
| fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++])); |
| break; |
| default: { // Scalars. |
| auto size = GetTypeSize(base_type); |
| CopyInline(fbb, fielddef, table, size, size); |
| break; |
| } |
| } |
| } |
| FLATBUFFERS_ASSERT(offset_idx == offsets.size()); |
| if (objectdef.is_struct()) { |
| fbb.ClearOffsets(); |
| return fbb.EndStruct(); |
| } else { |
| return fbb.EndTable(start); |
| } |
| } |
| |
| |
| bool Verify(const reflection::Schema &schema, const reflection::Object &root, |
| const uint8_t *const buf, const size_t length, |
| const uoffset_t max_depth, const uoffset_t max_tables) { |
| Verifier v(buf, length, max_depth, max_tables); |
| return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), |
| /*required=*/true); |
| } |
| |
| bool VerifySizePrefixed(const reflection::Schema &schema, |
| const reflection::Object &root, |
| const uint8_t *const buf, const size_t length, |
| const uoffset_t max_depth, const uoffset_t max_tables) { |
| Verifier v(buf, length, max_depth, max_tables); |
| return VerifyObject(v, schema, root, flatbuffers::GetAnySizePrefixedRoot(buf), |
| /*required=*/true); |
| } |
| |
| } // namespace flatbuffers |