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