Branch data Line data Source code
1 : : #include <stdio.h>
2 : : #include <stdlib.h>
3 : : #include "flatcc/reflection/reflection_builder.h"
4 : : #include "symbols.h"
5 : : #include "parser.h"
6 : : #include "codegen.h"
7 : : #include "fileio.h"
8 : : /* Needed to store length prefix. */
9 : : #include "catalog.h"
10 : :
11 : : #define BaseType(x) FLATBUFFERS_WRAP_NAMESPACE(reflection_BaseType, x)
12 : :
13 : 69 : static reflection_Type_ref_t export_type(flatcc_builder_t *B, fb_value_t type)
14 : : {
15 : : fb_scalar_type_t st = fb_missing_type;
16 : : int32_t index = -1;
17 : : reflection_BaseType_enum_t base_type = BaseType(None);
18 : : reflection_BaseType_enum_t element = BaseType(None);
19 : : reflection_BaseType_enum_t primitive = BaseType(None);
20 : :
21 [ + + + + : 69 : switch (type.type) {
- + + ]
22 : : case vt_scalar_type:
23 : 38 : st = type.st;
24 : 38 : break;
25 : : case vt_vector_type:
26 : 4 : st = type.st;
27 : : base_type = BaseType(Vector);
28 : 4 : break;
29 : : case vt_vector_string_type:
30 : : element = BaseType(String);
31 : : base_type = BaseType(Vector);
32 : 1 : break;
33 : : case vt_vector_compound_type_ref:
34 : 3 : index = (int32_t)type.ct->export_index;
35 [ - + - ]: 3 : switch (type.ct->symbol.kind) {
36 : : case fb_is_enum:
37 : 0 : st = type.ct->type.st;
38 : : base_type = BaseType(Vector);
39 : 0 : break;
40 : : case fb_is_struct:
41 : : case fb_is_table:
42 : : base_type = BaseType(Vector);
43 : : element = BaseType(Obj);
44 : 3 : break;
45 : : default:
46 : : break;
47 : : }
48 : : break;
49 : : case vt_string:
50 : : base_type = BaseType(String);
51 : 0 : break;
52 : : case vt_compound_type_ref:
53 : 18 : index = (int32_t)type.ct->export_index;
54 [ + + - + ]: 18 : switch (type.ct->symbol.kind) {
55 : : case fb_is_enum:
56 : 8 : st = type.ct->type.st;
57 : 8 : break;
58 : : case fb_is_struct:
59 : : case fb_is_table:
60 : : base_type = BaseType(Obj);
61 : : break;
62 : : case fb_is_union:
63 : : base_type = BaseType(Union);
64 : 2 : break;
65 : : default:
66 : : index = -1;
67 [ + + ]: 69 : break;
68 : : }
69 : : break;
70 : : default:
71 : : break;
72 : : }
73 : : /* If st is set, resolve scalar type and set it to base_type or element. */
74 : : switch (st) {
75 : : case fb_missing_type: break;
76 : : case fb_ulong: primitive = BaseType(ULong); break;
77 : : case fb_uint: primitive = BaseType(UInt); break;
78 : : case fb_ushort: primitive = BaseType(UShort); break;
79 : : case fb_ubyte: primitive = BaseType(UByte); break;
80 : : case fb_bool: primitive = BaseType(Bool); break;
81 : : case fb_long: primitive = BaseType(Long); break;
82 : : case fb_int: primitive = BaseType(Int); break;
83 : : case fb_short: primitive = BaseType(Short); break;
84 : : case fb_byte: primitive = BaseType(Byte); break;
85 : : case fb_double: primitive = BaseType(Double); break;
86 : : case fb_float: primitive = BaseType(Float); break;
87 : : default: break;
88 : : }
89 : :
90 [ + + ]: 69 : if (base_type == BaseType(None)) {
91 : : base_type = primitive;
92 [ + + ]: 18 : } else if (base_type == BaseType(Vector)) {
93 [ + + ]: 8 : if (element == BaseType(None)) {
94 : : element = primitive;
95 : : }
96 : : }
97 : 69 : return reflection_Type_create(B, base_type, element, index);
98 : : }
99 : :
100 : 30 : static void export_fields(flatcc_builder_t *B, fb_compound_type_t *ct)
101 : : {
102 : : fb_symbol_t *sym;
103 : : fb_member_t *member;
104 : : flatbuffers_bool_t has_key, deprecated, required, key_processed = 0;
105 : : int64_t default_integer;
106 : : double default_real;
107 : :
108 [ + + ]: 78 : for (sym = ct->members; sym; sym = sym->link) {
109 : : member = (fb_member_t *)sym;
110 : : /*
111 : : * Unlike `flatc` we allow multiple keys in the parser, but
112 : : * there is no way to tell which key is default in the
113 : : * reflection schema because the fields are sorted, so we only
114 : : * export the default (first) key.
115 : : */
116 [ + + ][ + + ]: 63 : has_key = !key_processed && (member->metadata_flags & fb_f_key) != 0;
117 : 63 : required = (member->metadata_flags & fb_f_required) != 0;
118 : : default_integer = 0;
119 : : default_real = 0.0;
120 : 63 : deprecated = (member->metadata_flags & fb_f_deprecated) != 0;
121 : :
122 [ + + ][ + + ]: 63 : if (member->type.type == vt_compound_type_ref && member->type.ct->symbol.kind == fb_is_union) {
123 : : reflection_Field_vec_push_start(B);
124 : : reflection_Field_name_start(B);
125 : 2 : reflection_Field_name_append(B, member->symbol.ident->text, member->symbol.ident->len);
126 : : reflection_Field_name_append(B, "_type", 5);
127 : 2 : reflection_Field_name_end(B);
128 : 2 : reflection_Field_type_create(B, BaseType(UType), BaseType(None), -1);
129 : 2 : reflection_Field_offset_add(B, (uint16_t)(member->id - 1 + 2) * sizeof(flatbuffers_voffset_t));
130 : 2 : reflection_Field_id_add(B, (uint16_t)(member->id - 1));
131 : 2 : reflection_Field_deprecated_add(B, deprecated);
132 : 2 : reflection_Field_vec_push_end(B);
133 : : }
134 : : reflection_Field_vec_push_start(B);
135 : 63 : reflection_Field_name_create(B, member->symbol.ident->text, member->symbol.ident->len);
136 : 63 : reflection_Field_type_add(B, export_type(B, member->type));
137 [ + + - ]: 63 : switch (ct->symbol.kind) {
138 : : case fb_is_table:
139 [ + + + - : 52 : switch (member->value.type) {
+ ]
140 : : case vt_uint:
141 : 9 : default_integer = (int64_t)member->value.u;
142 : : break;
143 : : case vt_int:
144 : 19 : default_integer = (int64_t)member->value.i;
145 : : break;
146 : : case vt_bool:
147 : 2 : default_integer = (int64_t)member->value.b;
148 : : break;
149 : : case vt_float:
150 : 0 : default_real = member->value.f;
151 : : break;
152 : : }
153 : 52 : reflection_Field_default_integer_add(B, default_integer);
154 : 52 : reflection_Field_default_real_add(B, default_real);
155 : 52 : reflection_Field_id_add(B, (uint16_t)member->id);
156 : 52 : reflection_Field_offset_add(B, (uint16_t)(member->id + 2) * sizeof(flatbuffers_voffset_t));
157 : 52 : reflection_Field_key_add(B, has_key);
158 : 52 : reflection_Field_required_add(B, required);
159 : : break;
160 : : case fb_is_struct:
161 : 11 : reflection_Field_offset_add(B, (uint16_t)member->offset);
162 : : break;
163 : : default: break;
164 : : }
165 : : /* Deprecated struct fields not supported by `flatc` but is here as an option. */
166 : 63 : reflection_Field_deprecated_add(B, deprecated);
167 : 63 : reflection_Field_vec_push_end(B);
168 : 63 : key_processed |= has_key;
169 : : }
170 : 15 : }
171 : :
172 : : /* `vec` is filled with references to the constructed objects. */
173 : 2 : static void export_objects(flatcc_builder_t *B, object_entry_t *objects, int nobjects,
174 : : reflection_Object_ref_t *object_map)
175 : : {
176 : : int i, is_struct;
177 : : fb_compound_type_t *ct;
178 : :
179 [ + + ]: 17 : for (i = 0; i < nobjects; ++i) {
180 : 15 : ct = objects[i].ct;
181 : : reflection_Object_start(B);
182 : 15 : reflection_Object_name_create_str(B, objects[i].name);
183 : : /*
184 : : * We can post sort-fields because the index is not used, unlike
185 : : * objects and enums.
186 : : */
187 : : reflection_Object_fields_start(B);
188 : 15 : export_fields(B, ct);
189 : 15 : reflection_Object_fields_end(B);
190 : 15 : is_struct = ct->symbol.kind == fb_is_struct;
191 [ + + ]: 15 : if (is_struct) {
192 : 6 : reflection_Object_bytesize_add(B, (uint32_t)ct->size);
193 : : }
194 : 15 : reflection_Object_is_struct_add(B, is_struct);
195 : 15 : reflection_Object_minalign_add(B, ct->align);
196 : 30 : object_map[i] = reflection_Object_end(B);
197 : : }
198 : 2 : reflection_Schema_objects_create(B, object_map, nobjects);
199 : 2 : }
200 : :
201 : 14 : static void export_enumval(flatcc_builder_t *B, fb_member_t *member, reflection_Object_ref_t *object_map)
202 : : {
203 : : reflection_EnumVal_vec_push_start(B);
204 : 14 : reflection_EnumVal_name_create(B, member->symbol.ident->text, member->symbol.ident->len);
205 [ + + ][ + + ]: 14 : if (object_map && member->type.type == vt_compound_type_ref) {
206 : 3 : reflection_EnumVal_object_add(B, object_map[member->type.ct->export_index]);
207 : : }
208 : 14 : reflection_EnumVal_value_add(B, member->value.u);
209 : 14 : reflection_EnumVal_vec_push_end(B);
210 : 14 : }
211 : :
212 : 2 : static void export_enums(flatcc_builder_t *B, enum_entry_t *enums, int nenums,
213 : : reflection_Object_ref_t *object_map)
214 : : {
215 : : int i, is_union;
216 : : fb_compound_type_t *ct;
217 : : fb_symbol_t *sym;
218 : : reflection_Enum_ref_t *vec;
219 : :
220 : : reflection_Schema_enums_start(B);
221 : 2 : vec = reflection_Schema_enums_extend(B, nenums);
222 [ + + ]: 8 : for (i = 0; i < nenums; ++i) {
223 : 6 : ct = enums[i].ct;
224 : 6 : is_union = ct->symbol.kind == fb_is_union;
225 : : reflection_Enum_start(B);
226 : 6 : reflection_Enum_name_create_str(B, enums[i].name);
227 : : reflection_Enum_values_start(B);
228 [ + + ]: 20 : for (sym = ct->members; sym; sym = sym->link) {
229 [ + + ]: 14 : export_enumval(B, (fb_member_t *)sym, is_union ? object_map : 0);
230 : : }
231 : 6 : reflection_Enum_values_end(B);
232 : 6 : reflection_Enum_is_union_add(B, is_union);
233 : 6 : reflection_Enum_underlying_type_add(B, export_type(B, ct->type));
234 : 12 : vec[i] = reflection_Enum_end(B);
235 : : }
236 : 2 : reflection_Schema_enums_end(B);
237 : 2 : }
238 : :
239 : 2 : static void export_root_type(flatcc_builder_t *B, fb_symbol_t * root_type,
240 : : reflection_Object_ref_t *object_map)
241 : : {
242 : : fb_compound_type_t *ct;
243 [ + - ]: 2 : if (root_type) {
244 : : /*
245 : : * We could also store a struct object here, but since the
246 : : * binrary schema says root_table, not root_type as in the text
247 : : * schema, it would be misleading.
248 : : */
249 [ + - ]: 2 : if (root_type->kind == fb_is_table) {
250 : : ct = (fb_compound_type_t *)root_type;
251 : 2 : reflection_Schema_root_table_add(B, object_map[ct->export_index]);
252 : : }
253 : : }
254 : 2 : }
255 : :
256 : 4 : static int export_schema(flatcc_builder_t *B, fb_options_t *opts, fb_schema_t *S)
257 : : {
258 : : catalog_t catalog;
259 : : reflection_Object_ref_t *object_map = 0;
260 : :
261 [ + - ]: 2 : if (build_catalog(&catalog, S, opts->bgen_qualify_names, &S->root_schema->scope_index)) {
262 : : return -1;
263 : : }
264 : :
265 [ + - ][ - + ]: 2 : if (catalog.nobjects > 0 && !(object_map = malloc(catalog.nobjects * sizeof(object_map[0])))) {
266 : 0 : clear_catalog(&catalog);
267 : : return -1;
268 : : }
269 : :
270 : : /* Build the schema. */
271 : :
272 [ - + ]: 2 : if (opts->bgen_length_prefix) {
273 : 0 : reflection_Schema_start_as_root_with_size(B);
274 : : } else {
275 : 2 : reflection_Schema_start_as_root(B);
276 : : }
277 [ + + ]: 2 : if (S->file_identifier.type == vt_string) {
278 : 1 : reflection_Schema_file_ident_create(B,
279 : 2 : S->file_identifier.s.s, S->file_identifier.s.len);
280 : : }
281 [ + + ]: 2 : if (S->file_extension.type == vt_string) {
282 : 1 : reflection_Schema_file_ext_create(B,
283 : 2 : S->file_extension.s.s, S->file_extension.s.len);
284 : : }
285 : 2 : export_objects(B, catalog.objects, catalog.nobjects, object_map);
286 : 2 : export_enums(B, catalog.enums, catalog.nenums, object_map);
287 : 2 : export_root_type(B, S->root_type.type, object_map);
288 : :
289 : 2 : reflection_Schema_end_as_root(B);
290 : :
291 : : /* Clean up support datastructures. */
292 : :
293 : 2 : clear_catalog(&catalog);
294 [ + - ]: 2 : if (object_map) {
295 : 2 : free(object_map);
296 : : }
297 : : return 0;
298 : : }
299 : :
300 : : /* Field sorting is easier done on the finished buffer. */
301 : 2 : static void sort_fields(void *buffer)
302 : : {
303 : : size_t i;
304 : : reflection_Schema_table_t schema;
305 : : reflection_Object_vec_t objects;
306 : : reflection_Object_table_t object;
307 : : reflection_Field_vec_t fields;
308 : : reflection_Field_mutable_vec_t mfields;
309 : :
310 : : schema = reflection_Schema_as_root(buffer);
311 : : objects = reflection_Schema_objects(schema);
312 [ + + ]: 34 : for (i = 0; i < reflection_Object_vec_len(objects); ++i) {
313 : : object = reflection_Object_vec_at(objects, i);
314 : : fields = reflection_Object_fields(object);
315 : : mfields = (reflection_Field_mutable_vec_t)fields;
316 : : reflection_Field_vec_sort(mfields);
317 : : }
318 : 2 : }
319 : :
320 : 2 : static FILE *open_file(fb_options_t *opts, fb_schema_t *S)
321 : : {
322 : : FILE *fp = 0;
323 : : char *path;
324 [ + - ]: 2 : const char *prefix = opts->outpath ? opts->outpath : "";
325 : 2 : size_t len, prefix_len = strlen(prefix);
326 : : const char *name;
327 : : const char *ext;
328 : :
329 : 2 : name = S->basename;
330 : 2 : len = strlen(name);
331 : :
332 : : ext = flatbuffers_extension;
333 : :
334 : : /* We generally should not use cgen options here, but in this case it makes sense. */
335 [ - + ]: 2 : if (opts->gen_stdout) {
336 : 0 : return stdout;
337 : : }
338 : 2 : checkmem((path = fb_create_join_path_n(prefix, prefix_len, name, len, ext, 1)));
339 : 2 : fp = fopen(path, "wb");
340 [ - + ]: 2 : if (!fp) {
341 : 0 : fprintf(stderr, "error opening file for writing binary schema: %s\n", path);
342 : : }
343 : 2 : free(path);
344 : : return fp;
345 : : }
346 : :
347 : : static void close_file(FILE *fp)
348 : : {
349 [ + - ]: 2 : if (fp && fp != stdout) {
350 : 2 : fclose(fp);
351 : : }
352 : : }
353 : :
354 : : /*
355 : : * Normally enums are required to be ascending in the schema and
356 : : * therefore there is no need to sort enums. If not, we export them in
357 : : * the order defined anyway becuase there is no well-defined ordering
358 : : * and blindly sorting the content would just loose more information.
359 : : *
360 : : * In conclusion: find by enum value is only support when enums are
361 : : * defined in consequtive order.
362 : : *
363 : : * refers to: `opts->ascending_enum`
364 : : *
365 : : * `size` must hold the maximum buffer size.
366 : : * Returns intput buffer if successful and updates size argument.
367 : : */
368 : 0 : void *fb_codegen_bfbs_to_buffer(fb_options_t *opts, fb_schema_t *S, void *buffer, size_t *size)
369 : : {
370 : : flatcc_builder_t builder, *B;
371 : :
372 : : B = &builder;
373 : 0 : flatcc_builder_init(B);
374 : 0 : export_schema(B, opts, S);
375 [ # # ]: 0 : if (!flatcc_builder_copy_buffer(B, buffer, *size)) {
376 : : goto done;
377 : : }
378 : 0 : sort_fields(buffer);
379 : : done:
380 : 0 : *size = flatcc_builder_get_buffer_size(B);
381 : 0 : flatcc_builder_clear(B);
382 : 0 : return buffer;
383 : : }
384 : :
385 : : /*
386 : : * Like to_buffer, but returns allocated buffer.
387 : : * Updates size argument with buffer size if not null.
388 : : * Returned buffer must be deallocatd with `free`.
389 : : * The buffer is malloc aligned which should suffice for reflection buffers.
390 : : */
391 : 2 : void *fb_codegen_bfbs_alloc_buffer(fb_options_t *opts, fb_schema_t *S, size_t *size)
392 : : {
393 : : flatcc_builder_t builder, *B;
394 : : void *buffer = 0;
395 : :
396 : : B = &builder;
397 : 2 : flatcc_builder_init(B);
398 [ + - ]: 2 : if (export_schema(B, opts, S)) {
399 : : goto done;
400 : : }
401 [ + - ]: 2 : if (!(buffer = flatcc_builder_finalize_buffer(B, size))) {
402 : : goto done;
403 : : }
404 : 2 : sort_fields(buffer);
405 : : done:
406 : 2 : flatcc_builder_clear(B);
407 : 2 : return buffer;
408 : : }
409 : :
410 : 2 : int fb_codegen_bfbs_to_file(fb_options_t *opts, fb_schema_t *S)
411 : : {
412 : : void *buffer;
413 : : size_t size;
414 : : FILE *fp;
415 : : int ret = -1;
416 : :
417 : 2 : fp = open_file(opts, S);
418 [ + - ]: 2 : if (!fp) {
419 : : return -1;
420 : : }
421 : 2 : buffer = fb_codegen_bfbs_alloc_buffer(opts, S, &size);
422 [ - + ]: 2 : if (!buffer) {
423 : 0 : printf("failed to generate binary schema\n");
424 : 0 : goto done;
425 : : }
426 [ - + ]: 2 : if (size != fwrite(buffer, 1, size, fp)) {
427 : 0 : fprintf(stderr, "could not write binary schema to file\n");
428 : 0 : goto done;
429 : : }
430 : : ret = 0;
431 : : done:
432 [ + - ]: 2 : if (buffer) {
433 : 2 : free(buffer);
434 : : }
435 : : close_file(fp);
436 : : return ret;
437 : : }
|