bfbs2json.c (9710B)
1 #include "flatcc/support/readfile.h" 2 #include "flatcc/reflection/reflection_reader.h" 3 4 /* -DFLATCC_PORTABLE may help if inttypes.h is missing. */ 5 #ifndef PRId64 6 #include <inttypes.h> 7 #endif 8 9 10 /* 11 * Reads a binary schema generated by `flatcc` or Googles `flatc` tool, 12 * then prints the content out in a custom JSON format. 13 * 14 * Note: This is completely unrelated to `flatcc's` JSON support - we 15 * just needed to do something tangible with the data we read from the 16 * binary schema and opted to print it as JSON. 17 * 18 * The JSON can be pretty printed with an external tool, for example: 19 * 20 * cat monster_test_schema.json | jq '.' 21 */ 22 23 void print_type(reflection_Type_table_t T) 24 { 25 int first = 1; 26 printf("{"); 27 if (reflection_Type_base_type_is_present(T)) { 28 if (!first) { 29 printf(","); 30 } 31 printf("\"base_type\":\"%s\"", reflection_BaseType_name(reflection_Type_base_type(T))); 32 first = 0; 33 } 34 if (reflection_Type_element_is_present(T)) { 35 if (!first) { 36 printf(","); 37 } 38 printf("\"element\":\"%s\"", reflection_BaseType_name(reflection_Type_element(T))); 39 first = 0; 40 } 41 if (reflection_Type_index_is_present(T)) { 42 if (!first) { 43 printf(","); 44 } 45 printf("\"index\":%d", reflection_Type_index(T)); 46 first = 0; 47 } 48 if (reflection_Type_fixed_length_is_present(T)) { 49 if (!first) { 50 printf(","); 51 } 52 printf("\"fixed_length\":%d", reflection_Type_fixed_length(T)); 53 first = 0; 54 } 55 printf("}"); 56 } 57 58 void print_attributes(reflection_KeyValue_vec_t KV) 59 { 60 size_t i; 61 reflection_KeyValue_table_t attribute; 62 const char *key, *value; 63 64 printf("["); 65 for (i = 0; i < reflection_KeyValue_vec_len(KV); ++i) { 66 attribute = reflection_KeyValue_vec_at(KV, i); 67 key = reflection_KeyValue_key(attribute); 68 value = reflection_KeyValue_value(attribute); 69 if (i > 0) { 70 printf(","); 71 } 72 printf("{\"key\":\"%s\"", key); 73 if (value) { 74 /* TODO: we ought to escape '\"' and other non-string-able characters. */ 75 printf(",\"value\":\"%s\"", value); 76 } 77 printf("}"); 78 } 79 printf("]"); 80 } 81 82 void print_object(reflection_Object_table_t O) 83 { 84 reflection_Field_vec_t Flds; 85 reflection_Field_table_t F; 86 size_t i; 87 88 Flds = reflection_Object_fields(O); 89 printf("{\"name\":\"%s\"", reflection_Object_name(O)); 90 printf(",\"fields\":["); 91 for (i = 0; i < reflection_Field_vec_len(Flds); ++i) { 92 if (i > 0) { 93 printf(","); 94 } 95 F = reflection_Field_vec_at(Flds, i); 96 printf("{\"name\":\"%s\",\"type\":", reflection_Field_name(F)); 97 print_type(reflection_Field_type(F)); 98 if (reflection_Field_id_is_present(F)) { 99 printf(",\"id\":%hu", reflection_Field_id(F)); 100 } 101 if (reflection_Field_default_integer_is_present(F)) { 102 printf(",\"default_integer\":%"PRId64"", (int64_t)reflection_Field_default_integer(F)); 103 } 104 if (reflection_Field_default_real_is_present(F)) { 105 printf(",\"default_integer\":%lf", reflection_Field_default_real(F)); 106 } 107 if (reflection_Field_required_is_present(F)) { 108 printf(",\"required\":%s", reflection_Field_required(F) ? "true" : "false"); 109 } 110 if (reflection_Field_key_is_present(F)) { 111 printf(",\"key\":%s", reflection_Field_key(F) ? "true" : "false"); 112 } 113 if (reflection_Field_attributes_is_present(F)) { 114 printf(",\"attributes\":"); 115 print_attributes(reflection_Field_attributes(F)); 116 } 117 printf("}"); 118 } 119 printf("]"); 120 if (reflection_Object_is_struct_is_present(O)) { 121 printf(",\"is_struct\":%s", reflection_Object_is_struct(O) ? "true" : "false"); 122 } 123 if (reflection_Object_minalign_is_present(O)) { 124 printf(",\"minalign\":%d", reflection_Object_minalign(O)); 125 } 126 if (reflection_Object_bytesize_is_present(O)) { 127 printf(",\"bytesize\":%d", reflection_Object_bytesize(O)); 128 } 129 if (reflection_Object_attributes_is_present(O)) { 130 printf(",\"attributes\":"); 131 print_attributes(reflection_Object_attributes(O)); 132 } 133 printf("}"); 134 } 135 136 void print_enum(reflection_Enum_table_t E) 137 { 138 reflection_EnumVal_vec_t EnumVals; 139 reflection_EnumVal_table_t EV; 140 size_t i; 141 142 printf("{\"name\":\"%s\"", reflection_Enum_name(E)); 143 EnumVals = reflection_Enum_values(E); 144 printf(",\"values\":["); 145 for (i = 0; i < reflection_Enum_vec_len(EnumVals); ++i) { 146 EV = reflection_EnumVal_vec_at(EnumVals, i); 147 if (i > 0) { 148 printf(","); 149 } 150 printf("{\"name\":\"%s\"", reflection_EnumVal_name(EV)); 151 if (reflection_EnumVal_value_is_present(EV)) { 152 printf(",\"value\":%"PRId64"", (int64_t)reflection_EnumVal_value(EV)); 153 } 154 if (reflection_EnumVal_object_is_present(EV)) { 155 printf(",\"object\":"); 156 print_object(reflection_EnumVal_object(EV)); 157 } 158 if (reflection_EnumVal_union_type_is_present(EV)) { 159 printf(",\"union_type\":"); 160 print_type(reflection_EnumVal_union_type(EV)); 161 } 162 printf("}"); 163 } 164 printf("]"); 165 if (reflection_Enum_is_union_is_present(E)) { 166 printf(",\"is_union\":%s", reflection_Enum_is_union(E) ? "true" : "false"); 167 } 168 printf(",\"underlying_type\":"); 169 print_type(reflection_Enum_underlying_type(E)); 170 if (reflection_Enum_attributes_is_present(E)) { 171 printf(",\"attributes\":"); 172 print_attributes(reflection_Enum_attributes(E)); 173 } 174 printf("}"); 175 } 176 177 void print_call(reflection_RPCCall_table_t C) 178 { 179 printf("{\"name\":\"%s\"", reflection_RPCCall_name(C)); 180 printf(",\"request\":"); 181 print_object(reflection_RPCCall_request(C)); 182 printf(",\"response\":"); 183 print_object(reflection_RPCCall_response(C)); 184 185 if (reflection_RPCCall_attributes_is_present(C)) { 186 printf(",\"attributes\":"); 187 print_attributes(reflection_RPCCall_attributes(C)); 188 } 189 printf("}"); 190 } 191 192 void print_service(reflection_Service_table_t S) 193 { 194 reflection_RPCCall_vec_t calls; 195 size_t i; 196 197 printf("{\"name\":\"%s\"", reflection_Service_name(S)); 198 199 printf(",\"calls\":["); 200 calls = reflection_Service_calls(S); 201 for (i = 0; i < reflection_RPCCall_vec_len(calls); ++i) { 202 if (i > 0) { 203 printf(","); 204 } 205 print_call(reflection_RPCCall_vec_at(calls, i)); 206 } 207 printf("]"); 208 209 if (reflection_Service_attributes_is_present(S)) { 210 printf(",\"attributes\":"); 211 print_attributes(reflection_Service_attributes(S)); 212 } 213 printf("}"); 214 } 215 216 void print_schema(reflection_Schema_table_t S) 217 { 218 reflection_Object_vec_t Objs; 219 reflection_Enum_vec_t Enums; 220 reflection_Service_vec_t Services; 221 size_t i; 222 223 Objs = reflection_Schema_objects(S); 224 printf("{"); 225 printf("\"objects\":["); 226 for (i = 0; i < reflection_Object_vec_len(Objs); ++i) { 227 if (i > 0) { 228 printf(","); 229 } 230 print_object(reflection_Object_vec_at(Objs, i)); 231 } 232 printf("]"); 233 Enums = reflection_Schema_enums(S); 234 printf(",\"enums\":["); 235 for (i = 0; i < reflection_Enum_vec_len(Enums); ++i) { 236 if (i > 0) { 237 printf(","); 238 } 239 print_enum(reflection_Enum_vec_at(Enums, i)); 240 } 241 printf("]"); 242 if (reflection_Schema_file_ident_is_present(S)) { 243 printf(",\"file_ident\":\"%s\"", reflection_Schema_file_ident(S)); 244 } 245 if (reflection_Schema_file_ext_is_present(S)) { 246 printf(",\"file_ext\":\"%s\"", reflection_Schema_file_ext(S)); 247 } 248 if (reflection_Schema_root_table_is_present(S)) { 249 printf(",\"root_table\":"); 250 print_object(reflection_Schema_root_table(S)); 251 } 252 if (reflection_Schema_services_is_present(S)) { 253 printf(",\"services\":["); 254 Services = reflection_Schema_services(S); 255 for (i = 0; i < reflection_Service_vec_len(Services); ++i) { 256 if (i > 0) { 257 printf(","); 258 } 259 print_service(reflection_Service_vec_at(Services, i)); 260 } 261 printf("]"); 262 } 263 printf("}\n"); 264 } 265 266 int load_and_dump_schema(const char *filename) 267 { 268 void *buffer; 269 size_t size; 270 int ret = -1; 271 reflection_Schema_table_t S; 272 273 buffer = readfile(filename, 100000, &size); 274 if (!buffer) { 275 fprintf(stderr, "failed to load binary schema file: '%s'\n", filename); 276 goto done; 277 } 278 if (size < 12) { 279 fprintf(stderr, "file too small to access: '%s'\n", filename); 280 goto done; 281 } 282 S = reflection_Schema_as_root(buffer); 283 if (!S) { 284 S = reflection_Schema_as_root((char*)buffer + 4); 285 if (S) { 286 fprintf(stderr, "(skipping length field of input buffer)\n"); 287 } 288 } 289 if (!S) { 290 fprintf(stderr, "input is not a valid schema"); 291 goto done; 292 } 293 print_schema(S); 294 ret = 0; 295 296 done: 297 if (buffer) { 298 free(buffer); 299 } 300 return ret; 301 } 302 303 int main(int argc, char *argv[]) 304 { 305 if (argc != 2) { 306 fprintf(stderr, "usage: bfbs2json <filename>\n"); 307 fprintf(stderr, "reads a binary flatbuffer schema and prints it to compact json on stdout\n\n"); 308 fprintf(stderr, "pretty print with exernal tool, for example:\n" 309 " bfbs2json myschema.bfbs | python -m json.tool > myschema.json\n" 310 "note: also understands binary schema files with a 4 byte length prefix\n"); 311 exit(-1); 312 } 313 return load_and_dump_schema(argv[1]); 314 }