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 | |
25 | namespace flatbuffers { |
26 | |
27 | void 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 | |
33 | void 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 | |
39 | void 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 | |
47 | void 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). |
59 | static 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 | |
72 | static bool IsStructOrTable(const reflection::BaseType base_type) { |
73 | return base_type == reflection::Obj; |
74 | } |
75 | |
76 | static bool IsScalar(const reflection::BaseType base_type) { |
77 | return base_type >= reflection::UType && base_type <= reflection::Double; |
78 | } |
79 | |
80 | static bool IsFloatingPoint(const reflection::BaseType base_type) { |
81 | return base_type == reflection::Float || base_type == reflection::Double; |
82 | } |
83 | |
84 | static bool IsBool(const reflection::BaseType base_type) { |
85 | return base_type == reflection::Bool; |
86 | } |
87 | |
88 | static bool IsSingleByte(const reflection::BaseType base_type) { |
89 | return base_type >= reflection::UType && base_type <= reflection::UByte; |
90 | } |
91 | |
92 | static bool IsVector(const reflection::BaseType base_type) { |
93 | return base_type == reflection::Vector; |
94 | } |
95 | |
96 | static 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 | |
110 | static 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 | |
121 | static 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. |
128 | class 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_ |