1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker * Copyright 2021 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker *
4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker *
8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker *
10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker */
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker #ifndef FLATBUFFERS_BFBS_GEN_H_
18*890232f2SAndroid Build Coastguard Worker #define FLATBUFFERS_BFBS_GEN_H_
19*890232f2SAndroid Build Coastguard Worker
20*890232f2SAndroid Build Coastguard Worker #include <cstdint>
21*890232f2SAndroid Build Coastguard Worker
22*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/bfbs_generator.h"
23*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/reflection_generated.h"
24*890232f2SAndroid Build Coastguard Worker
25*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
26*890232f2SAndroid Build Coastguard Worker
27*890232f2SAndroid Build Coastguard Worker namespace {
28*890232f2SAndroid Build Coastguard Worker
ForAllEnums(const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> * enums,std::function<void (const reflection::Enum *)> func)29*890232f2SAndroid Build Coastguard Worker static void ForAllEnums(
30*890232f2SAndroid Build Coastguard Worker const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
31*890232f2SAndroid Build Coastguard Worker std::function<void(const reflection::Enum *)> func) {
32*890232f2SAndroid Build Coastguard Worker for (auto it = enums->cbegin(); it != enums->cend(); ++it) { func(*it); }
33*890232f2SAndroid Build Coastguard Worker }
34*890232f2SAndroid Build Coastguard Worker
ForAllObjects(const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> * objects,std::function<void (const reflection::Object *)> func)35*890232f2SAndroid Build Coastguard Worker static void ForAllObjects(
36*890232f2SAndroid Build Coastguard Worker const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
37*890232f2SAndroid Build Coastguard Worker std::function<void(const reflection::Object *)> func) {
38*890232f2SAndroid Build Coastguard Worker for (auto it = objects->cbegin(); it != objects->cend(); ++it) { func(*it); }
39*890232f2SAndroid Build Coastguard Worker }
40*890232f2SAndroid Build Coastguard Worker
ForAllEnumValues(const reflection::Enum * enum_def,std::function<void (const reflection::EnumVal *)> func)41*890232f2SAndroid Build Coastguard Worker static void ForAllEnumValues(const reflection::Enum *enum_def,
42*890232f2SAndroid Build Coastguard Worker std::function<void(const reflection::EnumVal *)> func) {
43*890232f2SAndroid Build Coastguard Worker for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend();
44*890232f2SAndroid Build Coastguard Worker ++it) {
45*890232f2SAndroid Build Coastguard Worker func(*it);
46*890232f2SAndroid Build Coastguard Worker }
47*890232f2SAndroid Build Coastguard Worker }
48*890232f2SAndroid Build Coastguard Worker
ForAllDocumentation(const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> * documentation,std::function<void (const flatbuffers::String *)> func)49*890232f2SAndroid Build Coastguard Worker static void ForAllDocumentation(
50*890232f2SAndroid Build Coastguard Worker const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
51*890232f2SAndroid Build Coastguard Worker *documentation,
52*890232f2SAndroid Build Coastguard Worker std::function<void(const flatbuffers::String *)> func) {
53*890232f2SAndroid Build Coastguard Worker if (!documentation) { return; }
54*890232f2SAndroid Build Coastguard Worker for (auto it = documentation->cbegin(); it != documentation->cend(); ++it) {
55*890232f2SAndroid Build Coastguard Worker func(*it);
56*890232f2SAndroid Build Coastguard Worker }
57*890232f2SAndroid Build Coastguard Worker }
58*890232f2SAndroid Build Coastguard Worker
59*890232f2SAndroid Build Coastguard Worker // Maps the field index into object->fields() to the field's ID (the ith element
60*890232f2SAndroid Build Coastguard Worker // in the return vector).
FieldIdToIndex(const reflection::Object * object)61*890232f2SAndroid Build Coastguard Worker static std::vector<uint32_t> FieldIdToIndex(const reflection::Object *object) {
62*890232f2SAndroid Build Coastguard Worker std::vector<uint32_t> field_index_by_id;
63*890232f2SAndroid Build Coastguard Worker field_index_by_id.resize(object->fields()->size());
64*890232f2SAndroid Build Coastguard Worker
65*890232f2SAndroid Build Coastguard Worker // Create the mapping of field ID to the index into the vector.
66*890232f2SAndroid Build Coastguard Worker for (uint32_t i = 0; i < object->fields()->size(); ++i) {
67*890232f2SAndroid Build Coastguard Worker auto field = object->fields()->Get(i);
68*890232f2SAndroid Build Coastguard Worker field_index_by_id[field->id()] = i;
69*890232f2SAndroid Build Coastguard Worker }
70*890232f2SAndroid Build Coastguard Worker
71*890232f2SAndroid Build Coastguard Worker return field_index_by_id;
72*890232f2SAndroid Build Coastguard Worker }
73*890232f2SAndroid Build Coastguard Worker
IsStructOrTable(const reflection::BaseType base_type)74*890232f2SAndroid Build Coastguard Worker static bool IsStructOrTable(const reflection::BaseType base_type) {
75*890232f2SAndroid Build Coastguard Worker return base_type == reflection::Obj;
76*890232f2SAndroid Build Coastguard Worker }
77*890232f2SAndroid Build Coastguard Worker
IsFloatingPoint(const reflection::BaseType base_type)78*890232f2SAndroid Build Coastguard Worker static bool IsFloatingPoint(const reflection::BaseType base_type) {
79*890232f2SAndroid Build Coastguard Worker return base_type == reflection::Float || base_type == reflection::Double;
80*890232f2SAndroid Build Coastguard Worker }
81*890232f2SAndroid Build Coastguard Worker
IsBool(const reflection::BaseType base_type)82*890232f2SAndroid Build Coastguard Worker static bool IsBool(const reflection::BaseType base_type) {
83*890232f2SAndroid Build Coastguard Worker return base_type == reflection::Bool;
84*890232f2SAndroid Build Coastguard Worker }
85*890232f2SAndroid Build Coastguard Worker
IsSingleByte(const reflection::BaseType base_type)86*890232f2SAndroid Build Coastguard Worker static bool IsSingleByte(const reflection::BaseType base_type) {
87*890232f2SAndroid Build Coastguard Worker return base_type >= reflection::UType && base_type <= reflection::UByte;
88*890232f2SAndroid Build Coastguard Worker }
89*890232f2SAndroid Build Coastguard Worker
IsVector(const reflection::BaseType base_type)90*890232f2SAndroid Build Coastguard Worker static bool IsVector(const reflection::BaseType base_type) {
91*890232f2SAndroid Build Coastguard Worker return base_type == reflection::Vector;
92*890232f2SAndroid Build Coastguard Worker }
93*890232f2SAndroid Build Coastguard Worker
94*890232f2SAndroid Build Coastguard Worker } // namespace
95*890232f2SAndroid Build Coastguard Worker
96*890232f2SAndroid Build Coastguard Worker // A concrete base Flatbuffer Generator that specific language generators can
97*890232f2SAndroid Build Coastguard Worker // derive from.
98*890232f2SAndroid Build Coastguard Worker class BaseBfbsGenerator : public BfbsGenerator {
99*890232f2SAndroid Build Coastguard Worker public:
~BaseBfbsGenerator()100*890232f2SAndroid Build Coastguard Worker virtual ~BaseBfbsGenerator() {}
BaseBfbsGenerator()101*890232f2SAndroid Build Coastguard Worker BaseBfbsGenerator() : schema_(nullptr) {}
102*890232f2SAndroid Build Coastguard Worker
103*890232f2SAndroid Build Coastguard Worker virtual GeneratorStatus GenerateFromSchema(
104*890232f2SAndroid Build Coastguard Worker const reflection::Schema *schema) = 0;
105*890232f2SAndroid Build Coastguard Worker
106*890232f2SAndroid Build Coastguard Worker //
107*890232f2SAndroid Build Coastguard Worker virtual uint64_t SupportedAdvancedFeatures() const = 0;
108*890232f2SAndroid Build Coastguard Worker
109*890232f2SAndroid Build Coastguard Worker // Override of the Generator::generate method that does the initial
110*890232f2SAndroid Build Coastguard Worker // deserialization and verification steps.
Generate(const uint8_t * buffer,int64_t length)111*890232f2SAndroid Build Coastguard Worker GeneratorStatus Generate(const uint8_t *buffer,
112*890232f2SAndroid Build Coastguard Worker int64_t length) FLATBUFFERS_OVERRIDE {
113*890232f2SAndroid Build Coastguard Worker flatbuffers::Verifier verifier(buffer, static_cast<size_t>(length));
114*890232f2SAndroid Build Coastguard Worker if (!reflection::VerifySchemaBuffer(verifier)) {
115*890232f2SAndroid Build Coastguard Worker return FAILED_VERIFICATION;
116*890232f2SAndroid Build Coastguard Worker }
117*890232f2SAndroid Build Coastguard Worker
118*890232f2SAndroid Build Coastguard Worker // Store the root schema since there are cases where leaf nodes refer to
119*890232f2SAndroid Build Coastguard Worker // things in the root schema (e.g., indexing the objects).
120*890232f2SAndroid Build Coastguard Worker schema_ = reflection::GetSchema(buffer);
121*890232f2SAndroid Build Coastguard Worker
122*890232f2SAndroid Build Coastguard Worker const uint64_t advance_features = schema_->advanced_features();
123*890232f2SAndroid Build Coastguard Worker if (advance_features > SupportedAdvancedFeatures()) {
124*890232f2SAndroid Build Coastguard Worker return FAILED_VERIFICATION;
125*890232f2SAndroid Build Coastguard Worker }
126*890232f2SAndroid Build Coastguard Worker
127*890232f2SAndroid Build Coastguard Worker GeneratorStatus status = GenerateFromSchema(schema_);
128*890232f2SAndroid Build Coastguard Worker schema_ = nullptr;
129*890232f2SAndroid Build Coastguard Worker return status;
130*890232f2SAndroid Build Coastguard Worker }
131*890232f2SAndroid Build Coastguard Worker
132*890232f2SAndroid Build Coastguard Worker protected:
GetObject(const reflection::Type * type)133*890232f2SAndroid Build Coastguard Worker const reflection::Object *GetObject(const reflection::Type *type) const {
134*890232f2SAndroid Build Coastguard Worker if (type->index() >= 0 && IsStructOrTable(type->base_type())) {
135*890232f2SAndroid Build Coastguard Worker return GetObjectByIndex(type->index());
136*890232f2SAndroid Build Coastguard Worker }
137*890232f2SAndroid Build Coastguard Worker return nullptr;
138*890232f2SAndroid Build Coastguard Worker }
139*890232f2SAndroid Build Coastguard Worker
GetEnum(const reflection::Type * type)140*890232f2SAndroid Build Coastguard Worker const reflection::Enum *GetEnum(const reflection::Type *type) const {
141*890232f2SAndroid Build Coastguard Worker // TODO(derekbailey): it would be better to have a explicit list of allowed
142*890232f2SAndroid Build Coastguard Worker // base types, instead of negating Obj types.
143*890232f2SAndroid Build Coastguard Worker if (type->index() >= 0 && !IsStructOrTable(type->base_type())) {
144*890232f2SAndroid Build Coastguard Worker return GetEnumByIndex(type->index());
145*890232f2SAndroid Build Coastguard Worker }
146*890232f2SAndroid Build Coastguard Worker return nullptr;
147*890232f2SAndroid Build Coastguard Worker }
148*890232f2SAndroid Build Coastguard Worker
149*890232f2SAndroid Build Coastguard Worker // Used to get a object that is reference by index. (e.g.
150*890232f2SAndroid Build Coastguard Worker // reflection::Type::index). Returns nullptr if no object is available.
GetObjectByIndex(int32_t index)151*890232f2SAndroid Build Coastguard Worker const reflection::Object *GetObjectByIndex(int32_t index) const {
152*890232f2SAndroid Build Coastguard Worker if (!schema_ || index < 0 ||
153*890232f2SAndroid Build Coastguard Worker index >= static_cast<int32_t>(schema_->objects()->size())) {
154*890232f2SAndroid Build Coastguard Worker return nullptr;
155*890232f2SAndroid Build Coastguard Worker }
156*890232f2SAndroid Build Coastguard Worker return schema_->objects()->Get(index);
157*890232f2SAndroid Build Coastguard Worker }
158*890232f2SAndroid Build Coastguard Worker
159*890232f2SAndroid Build Coastguard Worker // Used to get a enum that is reference by index. (e.g.
160*890232f2SAndroid Build Coastguard Worker // reflection::Type::index). Returns nullptr if no enum is available.
GetEnumByIndex(int32_t index)161*890232f2SAndroid Build Coastguard Worker const reflection::Enum *GetEnumByIndex(int32_t index) const {
162*890232f2SAndroid Build Coastguard Worker if (!schema_ || index < 0 ||
163*890232f2SAndroid Build Coastguard Worker index >= static_cast<int32_t>(schema_->enums()->size())) {
164*890232f2SAndroid Build Coastguard Worker return nullptr;
165*890232f2SAndroid Build Coastguard Worker }
166*890232f2SAndroid Build Coastguard Worker return schema_->enums()->Get(index);
167*890232f2SAndroid Build Coastguard Worker }
168*890232f2SAndroid Build Coastguard Worker
ForAllFields(const reflection::Object * object,bool reverse,std::function<void (const reflection::Field *)> func)169*890232f2SAndroid Build Coastguard Worker void ForAllFields(const reflection::Object *object, bool reverse,
170*890232f2SAndroid Build Coastguard Worker std::function<void(const reflection::Field *)> func) const {
171*890232f2SAndroid Build Coastguard Worker const std::vector<uint32_t> field_to_id_map = FieldIdToIndex(object);
172*890232f2SAndroid Build Coastguard Worker for (size_t i = 0; i < field_to_id_map.size(); ++i) {
173*890232f2SAndroid Build Coastguard Worker func(object->fields()->Get(
174*890232f2SAndroid Build Coastguard Worker field_to_id_map[reverse ? field_to_id_map.size() - (i + 1) : i]));
175*890232f2SAndroid Build Coastguard Worker }
176*890232f2SAndroid Build Coastguard Worker }
177*890232f2SAndroid Build Coastguard Worker
178*890232f2SAndroid Build Coastguard Worker bool IsTable(const reflection::Type *type, bool use_element = false) const {
179*890232f2SAndroid Build Coastguard Worker return !IsStruct(type, use_element);
180*890232f2SAndroid Build Coastguard Worker }
181*890232f2SAndroid Build Coastguard Worker
182*890232f2SAndroid Build Coastguard Worker bool IsStruct(const reflection::Type *type, bool use_element = false) const {
183*890232f2SAndroid Build Coastguard Worker const reflection::BaseType base_type =
184*890232f2SAndroid Build Coastguard Worker use_element ? type->element() : type->base_type();
185*890232f2SAndroid Build Coastguard Worker return IsStructOrTable(base_type) &&
186*890232f2SAndroid Build Coastguard Worker GetObjectByIndex(type->index())->is_struct();
187*890232f2SAndroid Build Coastguard Worker }
188*890232f2SAndroid Build Coastguard Worker
189*890232f2SAndroid Build Coastguard Worker const reflection::Schema *schema_;
190*890232f2SAndroid Build Coastguard Worker };
191*890232f2SAndroid Build Coastguard Worker
192*890232f2SAndroid Build Coastguard Worker } // namespace flatbuffers
193*890232f2SAndroid Build Coastguard Worker
194*890232f2SAndroid Build Coastguard Worker #endif // FLATBUFFERS_BFBS_GEN_H_
195