#include "flatbuffers/reflection.h"
#include "flatbuffers/util.h"
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());
}
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; 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++) {
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: {
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;
}
}
int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
#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; }
#undef FLATBUFFERS_GET
}
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) {
auto &objectdef = *schema->objects()->Get(type_index);
auto s = objectdef.name()->str();
if (objectdef.is_struct()) {
s += "(struct)"; } 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)]"; case reflection::Union: return "(union)"; 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());
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) {
#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;
default: break;
}
#undef FLATBUFFERS_SET
}
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;
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;
}
default: SetAnyValueI(type, data, StringToInt(val)); break;
}
}
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; auto root = GetAnyRoot(buf_.data());
Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
ResizeTable(root_table ? *root_table : *schema.root_table(), root);
if (delta_ > 0)
buf_.insert(buf_.begin() + start, delta_, 0);
else
buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start);
}
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;
}
}
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; auto vtable = table->GetVTable();
auto tableloc = reinterpret_cast<uint8_t *>(table);
if (startptr_ <= tableloc) {
Straddle<soffset_t, -1>(vtable, table, table);
} else {
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
auto base_type = fielddef.type()->base_type();
if (base_type <= reflection::Double) continue;
auto offset = table->GetOptionalFieldOffset(fielddef.offset());
if (!offset) continue;
auto subobjectdef =
base_type == reflection::Obj
? schema_.objects()->Get(fielddef.type()->index())
: nullptr;
if (subobjectdef && subobjectdef->is_struct()) continue;
auto offsetloc = tableloc + offset;
if (DagCheck(offsetloc)) continue; auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
switch (base_type) {
case reflection::Obj: {
if (subobjectdef) {
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; 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);
}
}
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) {
memset(flatbuf->data() + start, 0, str->size());
ResizeContext ctx(schema, start, delta, flatbuf, root_table);
WriteScalar(flatbuf->data() + str_start,
static_cast<uoffset_t>(val.size()));
}
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) {
auto size_clear = -delta_elem * elem_size;
memset(flatbuf->data() + start - size_clear, 0, size_clear);
}
ResizeContext ctx(schema, start, delta_bytes, flatbuf, root_table);
WriteScalar(flatbuf->data() + vec_start, newsize); 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) {
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());
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) {
std::vector<uoffset_t> offsets;
auto fielddefs = objectdef.fields();
for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
auto &fielddef = **it;
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(); default: { auto element_size = GetTypeSize(element_base_type);
auto element_alignment = element_size; if (elemobjectdef && elemobjectdef->is_struct())
element_size = elemobjectdef->bytesize();
fbb.StartVector(vec->size(), element_size, element_alignment);
fbb.PushBytes(vec->Data(), element_size * vec->size());
offset = fbb.EndVector(vec->size());
break;
}
}
break;
}
default: break;
}
if (offset) { offsets.push_back(offset); }
}
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(); case reflection::Union:
case reflection::String:
case reflection::Vector:
fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
break;
default: { 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),
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),
true);
}
}