1 /*
2 * Copyright 2021 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 #ifndef FLATBUFFERS_BFBS_GEN_H_
18 #define FLATBUFFERS_BFBS_GEN_H_
19
20 #include <cstdint>
21
22 #include "flatbuffers/code_generator.h"
23 #include "flatbuffers/reflection_generated.h"
24
25 namespace flatbuffers {
26
27 namespace {
28
ForAllEnums(const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> * enums,std::function<void (const reflection::Enum *)> func)29 static void ForAllEnums(
30 const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums,
31 std::function<void(const reflection::Enum *)> func) {
32 for (auto it = enums->cbegin(); it != enums->cend(); ++it) { func(*it); }
33 }
34
ForAllObjects(const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> * objects,std::function<void (const reflection::Object *)> func)35 static void ForAllObjects(
36 const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects,
37 std::function<void(const reflection::Object *)> func) {
38 for (auto it = objects->cbegin(); it != objects->cend(); ++it) { func(*it); }
39 }
40
ForAllEnumValues(const reflection::Enum * enum_def,std::function<void (const reflection::EnumVal *)> func)41 static void ForAllEnumValues(
42 const reflection::Enum *enum_def,
43 std::function<void(const reflection::EnumVal *)> func) {
44 for (auto it = enum_def->values()->cbegin(); it != enum_def->values()->cend();
45 ++it) {
46 func(*it);
47 }
48 }
49
ForAllDocumentation(const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> * documentation,std::function<void (const flatbuffers::String *)> func)50 static void ForAllDocumentation(
51 const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
52 *documentation,
53 std::function<void(const flatbuffers::String *)> func) {
54 if (!documentation) { return; }
55 for (auto it = documentation->cbegin(); it != documentation->cend(); ++it) {
56 func(*it);
57 }
58 }
59
60 // Maps the field index into object->fields() to the field's ID (the ith element
61 // in the return vector).
FieldIdToIndex(const reflection::Object * object)62 static std::vector<uint32_t> FieldIdToIndex(const reflection::Object *object) {
63 std::vector<uint32_t> field_index_by_id;
64 field_index_by_id.resize(object->fields()->size());
65
66 // Create the mapping of field ID to the index into the vector.
67 for (uint32_t i = 0; i < object->fields()->size(); ++i) {
68 auto field = object->fields()->Get(i);
69 field_index_by_id[field->id()] = i;
70 }
71
72 return field_index_by_id;
73 }
74
IsStructOrTable(const reflection::BaseType base_type)75 static bool IsStructOrTable(const reflection::BaseType base_type) {
76 return base_type == reflection::Obj;
77 }
78
IsFloatingPoint(const reflection::BaseType base_type)79 static bool IsFloatingPoint(const reflection::BaseType base_type) {
80 return base_type == reflection::Float || base_type == reflection::Double;
81 }
82
IsBool(const reflection::BaseType base_type)83 static bool IsBool(const reflection::BaseType base_type) {
84 return base_type == reflection::Bool;
85 }
86
IsSingleByte(const reflection::BaseType base_type)87 static bool IsSingleByte(const reflection::BaseType base_type) {
88 return base_type >= reflection::UType && base_type <= reflection::UByte;
89 }
90
IsVector(const reflection::BaseType base_type)91 static bool IsVector(const reflection::BaseType base_type) {
92 return base_type == reflection::Vector;
93 }
94
95 } // namespace
96
97 // A concrete base Flatbuffer Generator that specific language generators can
98 // derive from.
99 class BaseBfbsGenerator : public CodeGenerator {
100 public:
~BaseBfbsGenerator()101 virtual ~BaseBfbsGenerator() {}
BaseBfbsGenerator()102 BaseBfbsGenerator() : schema_(nullptr) {}
103
104 virtual Status GenerateFromSchema(const reflection::Schema *schema,
105 const CodeGenOptions &options) = 0;
106
107 virtual uint64_t SupportedAdvancedFeatures() const = 0;
108
109 // Override of the Generator::GenerateCode method that does the initial
110 // deserialization and verification steps.
GenerateCode(const uint8_t * buffer,int64_t length,const CodeGenOptions & options)111 Status GenerateCode(const uint8_t *buffer, int64_t length,
112 const CodeGenOptions &options) FLATBUFFERS_OVERRIDE {
113 flatbuffers::Verifier verifier(buffer, static_cast<size_t>(length));
114 if (!reflection::VerifySchemaBuffer(verifier)) {
115 return FAILED_VERIFICATION;
116 }
117
118 // Store the root schema since there are cases where leaf nodes refer to
119 // things in the root schema (e.g., indexing the objects).
120 schema_ = reflection::GetSchema(buffer);
121
122 const uint64_t advance_features = schema_->advanced_features();
123 if (advance_features > SupportedAdvancedFeatures()) {
124 return FAILED_VERIFICATION;
125 }
126
127 Status status = GenerateFromSchema(schema_, options);
128 schema_ = nullptr;
129 return status;
130 }
131
132 protected:
133 // GetObject returns the underlying object struct of the given type
134 // if element_type is true and GetObject is a list of objects then
135 // GetObject will correctly return the object struct of the vector's elements
136 const reflection::Object *GetObject(const reflection::Type *type,
137 bool element_type = false) const {
138 const reflection::BaseType base_type =
139 element_type ? type->element() : type->base_type();
140 if (type->index() >= 0 && IsStructOrTable(base_type)) {
141 return GetObjectByIndex(type->index());
142 }
143 return nullptr;
144 }
145
146 // GetEnum returns the underlying enum struct of the given type
147 // if element_type is true and GetEnum is a list of enums then
148 // GetEnum will correctly return the enum struct of the vector's elements
149 const reflection::Enum *GetEnum(const reflection::Type *type,
150 bool element_type = false) const {
151 const reflection::BaseType base_type =
152 element_type ? type->element() : type->base_type();
153 // TODO(derekbailey): it would be better to have a explicit list of allowed
154 // base types, instead of negating Obj types.
155 if (type->index() >= 0 && !IsStructOrTable(base_type)) {
156 return GetEnumByIndex(type->index());
157 }
158 return nullptr;
159 }
160
161 // Used to get a object that is reference by index. (e.g.
162 // reflection::Type::index). Returns nullptr if no object is available.
GetObjectByIndex(int32_t index)163 const reflection::Object *GetObjectByIndex(int32_t index) const {
164 if (!schema_ || index < 0 ||
165 index >= static_cast<int32_t>(schema_->objects()->size())) {
166 return nullptr;
167 }
168 return schema_->objects()->Get(index);
169 }
170
171 // Used to get a enum that is reference by index. (e.g.
172 // reflection::Type::index). Returns nullptr if no enum is available.
GetEnumByIndex(int32_t index)173 const reflection::Enum *GetEnumByIndex(int32_t index) const {
174 if (!schema_ || index < 0 ||
175 index >= static_cast<int32_t>(schema_->enums()->size())) {
176 return nullptr;
177 }
178 return schema_->enums()->Get(index);
179 }
180
ForAllFields(const reflection::Object * object,bool reverse,std::function<void (const reflection::Field *)> func)181 void ForAllFields(const reflection::Object *object, bool reverse,
182 std::function<void(const reflection::Field *)> func) const {
183 const std::vector<uint32_t> field_to_id_map = FieldIdToIndex(object);
184 for (size_t i = 0; i < field_to_id_map.size(); ++i) {
185 func(object->fields()->Get(
186 field_to_id_map[reverse ? field_to_id_map.size() - (i + 1) : i]));
187 }
188 }
189
190 bool IsTable(const reflection::Type *type, bool use_element = false) const {
191 return !IsStruct(type, use_element);
192 }
193
194 bool IsStruct(const reflection::Type *type, bool use_element = false) const {
195 const reflection::BaseType base_type =
196 use_element ? type->element() : type->base_type();
197 return IsStructOrTable(base_type) &&
198 GetObjectByIndex(type->index())->is_struct();
199 }
200
201 const reflection::Schema *schema_;
202 };
203
204 } // namespace flatbuffers
205
206 #endif // FLATBUFFERS_BFBS_GEN_H_
207