/* * Copyright 2021 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. */ #ifndef FLATBUFFERS_BFBS_GEN_H_ #define FLATBUFFERS_BFBS_GEN_H_ #include #include "flatbuffers/code_generator.h" #include "flatbuffers/reflection_generated.h" namespace flatbuffers { namespace { static void ForAllEnums( const flatbuffers::Vector> *enums, std::function func) { for (auto it = enums->cbegin(); it != enums->cend(); ++it) { func(*it); } } static void ForAllObjects( const flatbuffers::Vector> *objects, std::function func) { for (auto it = objects->cbegin(); it != objects->cend(); ++it) { func(*it); } } static void ForAllEnumValues( const reflection::Enum *enum_def, std::function func) { for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend(); ++it) { func(*it); } } static void ForAllDocumentation( const flatbuffers::Vector> *documentation, std::function func) { if (!documentation) { return; } for (auto it = documentation->cbegin(); it != documentation->cend(); ++it) { func(*it); } } // Maps the field index into object->fields() to the field's ID (the ith element // in the return vector). static std::vector FieldIdToIndex(const reflection::Object *object) { std::vector field_index_by_id; field_index_by_id.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_index_by_id[field->id()] = i; } return field_index_by_id; } static bool IsStructOrTable(const reflection::BaseType base_type) { return base_type == reflection::Obj; } static bool IsFloatingPoint(const reflection::BaseType base_type) { return base_type == reflection::Float || base_type == reflection::Double; } static bool IsBool(const reflection::BaseType base_type) { return base_type == reflection::Bool; } static bool IsSingleByte(const reflection::BaseType base_type) { return base_type >= reflection::UType && base_type <= reflection::UByte; } static bool IsVector(const reflection::BaseType base_type) { return base_type == reflection::Vector; } } // namespace // A concrete base Flatbuffer Generator that specific language generators can // derive from. class BaseBfbsGenerator : public CodeGenerator { public: virtual ~BaseBfbsGenerator() {} BaseBfbsGenerator() : schema_(nullptr) {} virtual Status GenerateFromSchema(const reflection::Schema *schema, const CodeGenOptions &options) = 0; virtual uint64_t SupportedAdvancedFeatures() const = 0; // Override of the Generator::GenerateCode method that does the initial // deserialization and verification steps. Status GenerateCode(const uint8_t *buffer, int64_t length, const CodeGenOptions &options) FLATBUFFERS_OVERRIDE { flatbuffers::Verifier verifier(buffer, static_cast(length)); if (!reflection::VerifySchemaBuffer(verifier)) { return FAILED_VERIFICATION; } // Store the root schema since there are cases where leaf nodes refer to // things in the root schema (e.g., indexing the objects). schema_ = reflection::GetSchema(buffer); const uint64_t advance_features = schema_->advanced_features(); if (advance_features > SupportedAdvancedFeatures()) { return FAILED_VERIFICATION; } Status status = GenerateFromSchema(schema_, options); schema_ = nullptr; return status; } protected: // GetObject returns the underlying object struct of the given type // if element_type is true and GetObject is a list of objects then // GetObject will correctly return the object struct of the vector's elements const reflection::Object *GetObject(const reflection::Type *type, bool element_type = false) const { const reflection::BaseType base_type = element_type ? type->element() : type->base_type(); if (type->index() >= 0 && IsStructOrTable(base_type)) { return GetObjectByIndex(type->index()); } return nullptr; } // GetEnum returns the underlying enum struct of the given type // if element_type is true and GetEnum is a list of enums then // GetEnum will correctly return the enum struct of the vector's elements const reflection::Enum *GetEnum(const reflection::Type *type, bool element_type = false) const { const reflection::BaseType base_type = element_type ? type->element() : type->base_type(); // TODO(derekbailey): it would be better to have a explicit list of allowed // base types, instead of negating Obj types. if (type->index() >= 0 && !IsStructOrTable(base_type)) { return GetEnumByIndex(type->index()); } return nullptr; } // Used to get a object that is reference by index. (e.g. // reflection::Type::index). Returns nullptr if no object is available. const reflection::Object *GetObjectByIndex(int32_t index) const { if (!schema_ || index < 0 || index >= static_cast(schema_->objects()->size())) { return nullptr; } return schema_->objects()->Get(index); } // Used to get a enum that is reference by index. (e.g. // reflection::Type::index). Returns nullptr if no enum is available. const reflection::Enum *GetEnumByIndex(int32_t index) const { if (!schema_ || index < 0 || index >= static_cast(schema_->enums()->size())) { return nullptr; } return schema_->enums()->Get(index); } void ForAllFields(const reflection::Object *object, bool reverse, std::function func) const { const std::vector field_to_id_map = FieldIdToIndex(object); 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])); } } bool IsTable(const reflection::Type *type, bool use_element = false) const { return !IsStruct(type, use_element); } bool IsStruct(const reflection::Type *type, bool use_element = false) const { const reflection::BaseType base_type = use_element ? type->element() : type->base_type(); return IsStructOrTable(base_type) && GetObjectByIndex(type->index())->is_struct(); } const reflection::Schema *schema_; }; } // namespace flatbuffers #endif // FLATBUFFERS_BFBS_GEN_H_