#include "flatcc/support/readfile.h" #include "flatcc/reflection/reflection_reader.h" /* -DFLATCC_PORTABLE may help if inttypes.h is missing. */ #ifndef PRId64 #include #endif /* * Reads a binary schema generated by `flatcc` or Googles `flatc` tool, * then prints the content out in a custom JSON format. * * Note: This is completely unrelated to `flatcc's` JSON support - we * just needed to do something tangible with the data we read from the * binary schema and opted to print it as JSON. * * The JSON can be pretty printed with an external tool, for example: * * cat monster_test_schema.json | jq '.' */ void print_type(reflection_Type_table_t T) { int first = 1; printf("{"); if (reflection_Type_base_type_is_present(T)) { if (!first) { printf(","); } printf("\"base_type\":\"%s\"", reflection_BaseType_name(reflection_Type_base_type(T))); first = 0; } if (reflection_Type_element_is_present(T)) { if (!first) { printf(","); } printf("\"element\":\"%s\"", reflection_BaseType_name(reflection_Type_element(T))); first = 0; } if (reflection_Type_index_is_present(T)) { if (!first) { printf(","); } printf("\"index\":%d", reflection_Type_index(T)); first = 0; } if (reflection_Type_fixed_length_is_present(T)) { if (!first) { printf(","); } printf("\"fixed_length\":%d", reflection_Type_fixed_length(T)); first = 0; } printf("}"); } void print_attributes(reflection_KeyValue_vec_t KV) { size_t i; reflection_KeyValue_table_t attribute; const char *key, *value; printf("["); for (i = 0; i < reflection_KeyValue_vec_len(KV); ++i) { attribute = reflection_KeyValue_vec_at(KV, i); key = reflection_KeyValue_key(attribute); value = reflection_KeyValue_value(attribute); if (i > 0) { printf(","); } printf("{\"key\":\"%s\"", key); if (value) { /* TODO: we ought to escape '\"' and other non-string-able characters. */ printf(",\"value\":\"%s\"", value); } printf("}"); } printf("]"); } void print_object(reflection_Object_table_t O) { reflection_Field_vec_t Flds; reflection_Field_table_t F; size_t i; Flds = reflection_Object_fields(O); printf("{\"name\":\"%s\"", reflection_Object_name(O)); printf(",\"fields\":["); for (i = 0; i < reflection_Field_vec_len(Flds); ++i) { if (i > 0) { printf(","); } F = reflection_Field_vec_at(Flds, i); printf("{\"name\":\"%s\",\"type\":", reflection_Field_name(F)); print_type(reflection_Field_type(F)); if (reflection_Field_id_is_present(F)) { printf(",\"id\":%hu", reflection_Field_id(F)); } if (reflection_Field_default_integer_is_present(F)) { printf(",\"default_integer\":%"PRId64"", (int64_t)reflection_Field_default_integer(F)); } if (reflection_Field_default_real_is_present(F)) { printf(",\"default_integer\":%lf", reflection_Field_default_real(F)); } if (reflection_Field_required_is_present(F)) { printf(",\"required\":%s", reflection_Field_required(F) ? "true" : "false"); } if (reflection_Field_key_is_present(F)) { printf(",\"key\":%s", reflection_Field_key(F) ? "true" : "false"); } if (reflection_Field_attributes_is_present(F)) { printf(",\"attributes\":"); print_attributes(reflection_Field_attributes(F)); } printf("}"); } printf("]"); if (reflection_Object_is_struct_is_present(O)) { printf(",\"is_struct\":%s", reflection_Object_is_struct(O) ? "true" : "false"); } if (reflection_Object_minalign_is_present(O)) { printf(",\"minalign\":%d", reflection_Object_minalign(O)); } if (reflection_Object_bytesize_is_present(O)) { printf(",\"bytesize\":%d", reflection_Object_bytesize(O)); } if (reflection_Object_attributes_is_present(O)) { printf(",\"attributes\":"); print_attributes(reflection_Object_attributes(O)); } printf("}"); } void print_enum(reflection_Enum_table_t E) { reflection_EnumVal_vec_t EnumVals; reflection_EnumVal_table_t EV; size_t i; printf("{\"name\":\"%s\"", reflection_Enum_name(E)); EnumVals = reflection_Enum_values(E); printf(",\"values\":["); for (i = 0; i < reflection_Enum_vec_len(EnumVals); ++i) { EV = reflection_EnumVal_vec_at(EnumVals, i); if (i > 0) { printf(","); } printf("{\"name\":\"%s\"", reflection_EnumVal_name(EV)); if (reflection_EnumVal_value_is_present(EV)) { printf(",\"value\":%"PRId64"", (int64_t)reflection_EnumVal_value(EV)); } if (reflection_EnumVal_object_is_present(EV)) { printf(",\"object\":"); print_object(reflection_EnumVal_object(EV)); } if (reflection_EnumVal_union_type_is_present(EV)) { printf(",\"union_type\":"); print_type(reflection_EnumVal_union_type(EV)); } printf("}"); } printf("]"); if (reflection_Enum_is_union_is_present(E)) { printf(",\"is_union\":%s", reflection_Enum_is_union(E) ? "true" : "false"); } printf(",\"underlying_type\":"); print_type(reflection_Enum_underlying_type(E)); if (reflection_Enum_attributes_is_present(E)) { printf(",\"attributes\":"); print_attributes(reflection_Enum_attributes(E)); } printf("}"); } void print_call(reflection_RPCCall_table_t C) { printf("{\"name\":\"%s\"", reflection_RPCCall_name(C)); printf(",\"request\":"); print_object(reflection_RPCCall_request(C)); printf(",\"response\":"); print_object(reflection_RPCCall_response(C)); if (reflection_RPCCall_attributes_is_present(C)) { printf(",\"attributes\":"); print_attributes(reflection_RPCCall_attributes(C)); } printf("}"); } void print_service(reflection_Service_table_t S) { reflection_RPCCall_vec_t calls; size_t i; printf("{\"name\":\"%s\"", reflection_Service_name(S)); printf(",\"calls\":["); calls = reflection_Service_calls(S); for (i = 0; i < reflection_RPCCall_vec_len(calls); ++i) { if (i > 0) { printf(","); } print_call(reflection_RPCCall_vec_at(calls, i)); } printf("]"); if (reflection_Service_attributes_is_present(S)) { printf(",\"attributes\":"); print_attributes(reflection_Service_attributes(S)); } printf("}"); } void print_schema(reflection_Schema_table_t S) { reflection_Object_vec_t Objs; reflection_Enum_vec_t Enums; reflection_Service_vec_t Services; size_t i; Objs = reflection_Schema_objects(S); printf("{"); printf("\"objects\":["); for (i = 0; i < reflection_Object_vec_len(Objs); ++i) { if (i > 0) { printf(","); } print_object(reflection_Object_vec_at(Objs, i)); } printf("]"); Enums = reflection_Schema_enums(S); printf(",\"enums\":["); for (i = 0; i < reflection_Enum_vec_len(Enums); ++i) { if (i > 0) { printf(","); } print_enum(reflection_Enum_vec_at(Enums, i)); } printf("]"); if (reflection_Schema_file_ident_is_present(S)) { printf(",\"file_ident\":\"%s\"", reflection_Schema_file_ident(S)); } if (reflection_Schema_file_ext_is_present(S)) { printf(",\"file_ext\":\"%s\"", reflection_Schema_file_ext(S)); } if (reflection_Schema_root_table_is_present(S)) { printf(",\"root_table\":"); print_object(reflection_Schema_root_table(S)); } if (reflection_Schema_services_is_present(S)) { printf(",\"services\":["); Services = reflection_Schema_services(S); for (i = 0; i < reflection_Service_vec_len(Services); ++i) { if (i > 0) { printf(","); } print_service(reflection_Service_vec_at(Services, i)); } printf("]"); } printf("}\n"); } int load_and_dump_schema(const char *filename) { void *buffer; size_t size; int ret = -1; reflection_Schema_table_t S; buffer = readfile(filename, 100000, &size); if (!buffer) { fprintf(stderr, "failed to load binary schema file: '%s'\n", filename); goto done; } if (size < 12) { fprintf(stderr, "file too small to access: '%s'\n", filename); goto done; } S = reflection_Schema_as_root(buffer); if (!S) { S = reflection_Schema_as_root((char*)buffer + 4); if (S) { fprintf(stderr, "(skipping length field of input buffer)\n"); } } if (!S) { fprintf(stderr, "input is not a valid schema"); goto done; } print_schema(S); ret = 0; done: if (buffer) { free(buffer); } return ret; } int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "usage: bfbs2json \n"); fprintf(stderr, "reads a binary flatbuffer schema and prints it to compact json on stdout\n\n"); fprintf(stderr, "pretty print with exernal tool, for example:\n" " bfbs2json myschema.bfbs | python -m json.tool > myschema.json\n" "note: also understands binary schema files with a 4 byte length prefix\n"); exit(-1); } return load_and_dump_schema(argv[1]); }