idl_gen_text.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright 2014 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. // independent from idl_parser, since this code is not needed for most clients
  17. #include "flatbuffers/flatbuffers.h"
  18. #include "flatbuffers/idl.h"
  19. #include "flatbuffers/util.h"
  20. namespace flatbuffers {
  21. static void GenStruct(const StructDef &struct_def, const Table *table,
  22. int indent, const GeneratorOptions &opts,
  23. std::string *_text);
  24. // If indentation is less than 0, that indicates we don't want any newlines
  25. // either.
  26. const char *NewLine(const GeneratorOptions &opts) {
  27. return opts.indent_step >= 0 ? "\n" : "";
  28. }
  29. int Indent(const GeneratorOptions &opts) {
  30. return std::max(opts.indent_step, 0);
  31. }
  32. // Output an identifier with or without quotes depending on strictness.
  33. void OutputIdentifier(const std::string &name, const GeneratorOptions &opts,
  34. std::string *_text) {
  35. std::string &text = *_text;
  36. if (opts.strict_json) text += "\"";
  37. text += name;
  38. if (opts.strict_json) text += "\"";
  39. }
  40. // Print (and its template specialization below for pointers) generate text
  41. // for a single FlatBuffer value into JSON format.
  42. // The general case for scalars:
  43. template<typename T> void Print(T val, Type type, int /*indent*/,
  44. StructDef * /*union_sd*/,
  45. const GeneratorOptions &opts,
  46. std::string *_text) {
  47. std::string &text = *_text;
  48. if (type.enum_def && opts.output_enum_identifiers) {
  49. auto enum_val = type.enum_def->ReverseLookup(static_cast<int>(val));
  50. if (enum_val) {
  51. OutputIdentifier(enum_val->name, opts, _text);
  52. return;
  53. }
  54. }
  55. text += NumToString(val);
  56. }
  57. // Print a vector a sequence of JSON values, comma separated, wrapped in "[]".
  58. template<typename T> void PrintVector(const Vector<T> &v, Type type,
  59. int indent, const GeneratorOptions &opts,
  60. std::string *_text) {
  61. std::string &text = *_text;
  62. text += "[";
  63. text += NewLine(opts);
  64. for (uoffset_t i = 0; i < v.size(); i++) {
  65. if (i) {
  66. text += ",";
  67. text += NewLine(opts);
  68. }
  69. text.append(indent + Indent(opts), ' ');
  70. if (IsStruct(type))
  71. Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
  72. indent + Indent(opts), nullptr, opts, _text);
  73. else
  74. Print(v.Get(i), type, indent + Indent(opts), nullptr,
  75. opts, _text);
  76. }
  77. text += NewLine(opts);
  78. text.append(indent, ' ');
  79. text += "]";
  80. }
  81. static void EscapeString(const String &s, std::string *_text) {
  82. std::string &text = *_text;
  83. text += "\"";
  84. for (uoffset_t i = 0; i < s.size(); i++) {
  85. char c = s.Get(i);
  86. switch (c) {
  87. case '\n': text += "\\n"; break;
  88. case '\t': text += "\\t"; break;
  89. case '\r': text += "\\r"; break;
  90. case '\b': text += "\\b"; break;
  91. case '\f': text += "\\f"; break;
  92. case '\"': text += "\\\""; break;
  93. case '\\': text += "\\\\"; break;
  94. default:
  95. if (c >= ' ' && c <= '~') {
  96. text += c;
  97. } else {
  98. // Not printable ASCII data. Let's see if it's valid UTF-8 first:
  99. const char *utf8 = s.c_str() + i;
  100. int ucc = FromUTF8(&utf8);
  101. if (ucc >= 0x80 && ucc <= 0xFFFF) {
  102. // Parses as Unicode within JSON's \uXXXX range, so use that.
  103. text += "\\u";
  104. text += IntToStringHex(ucc, 4);
  105. // Skip past characters recognized.
  106. i = static_cast<uoffset_t>(utf8 - s.c_str() - 1);
  107. } else {
  108. // It's either unprintable ASCII, arbitrary binary, or Unicode data
  109. // that doesn't fit \uXXXX, so use \xXX escape code instead.
  110. text += "\\x";
  111. text += IntToStringHex(static_cast<uint8_t>(c), 2);
  112. }
  113. }
  114. break;
  115. }
  116. }
  117. text += "\"";
  118. }
  119. // Specialization of Print above for pointer types.
  120. template<> void Print<const void *>(const void *val,
  121. Type type, int indent,
  122. StructDef *union_sd,
  123. const GeneratorOptions &opts,
  124. std::string *_text) {
  125. switch (type.base_type) {
  126. case BASE_TYPE_UNION:
  127. // If this assert hits, you have an corrupt buffer, a union type field
  128. // was not present or was out of range.
  129. assert(union_sd);
  130. GenStruct(*union_sd,
  131. reinterpret_cast<const Table *>(val),
  132. indent,
  133. opts,
  134. _text);
  135. break;
  136. case BASE_TYPE_STRUCT:
  137. GenStruct(*type.struct_def,
  138. reinterpret_cast<const Table *>(val),
  139. indent,
  140. opts,
  141. _text);
  142. break;
  143. case BASE_TYPE_STRING: {
  144. EscapeString(*reinterpret_cast<const String *>(val), _text);
  145. break;
  146. }
  147. case BASE_TYPE_VECTOR:
  148. type = type.VectorType();
  149. // Call PrintVector above specifically for each element type:
  150. switch (type.base_type) {
  151. #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
  152. case BASE_TYPE_ ## ENUM: \
  153. PrintVector<CTYPE>( \
  154. *reinterpret_cast<const Vector<CTYPE> *>(val), \
  155. type, indent, opts, _text); break;
  156. FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
  157. #undef FLATBUFFERS_TD
  158. }
  159. break;
  160. default: assert(0);
  161. }
  162. }
  163. // Generate text for a scalar field.
  164. template<typename T> static void GenField(const FieldDef &fd,
  165. const Table *table, bool fixed,
  166. const GeneratorOptions &opts,
  167. int indent,
  168. std::string *_text) {
  169. Print(fixed ?
  170. reinterpret_cast<const Struct *>(table)->GetField<T>(fd.value.offset) :
  171. table->GetField<T>(fd.value.offset, 0), fd.value.type, indent, nullptr,
  172. opts, _text);
  173. }
  174. // Generate text for non-scalar field.
  175. static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
  176. int indent, StructDef *union_sd,
  177. const GeneratorOptions &opts, std::string *_text) {
  178. const void *val = nullptr;
  179. if (fixed) {
  180. // The only non-scalar fields in structs are structs.
  181. assert(IsStruct(fd.value.type));
  182. val = reinterpret_cast<const Struct *>(table)->
  183. GetStruct<const void *>(fd.value.offset);
  184. } else {
  185. val = IsStruct(fd.value.type)
  186. ? table->GetStruct<const void *>(fd.value.offset)
  187. : table->GetPointer<const void *>(fd.value.offset);
  188. }
  189. Print(val, fd.value.type, indent, union_sd, opts, _text);
  190. }
  191. // Generate text for a struct or table, values separated by commas, indented,
  192. // and bracketed by "{}"
  193. static void GenStruct(const StructDef &struct_def, const Table *table,
  194. int indent, const GeneratorOptions &opts,
  195. std::string *_text) {
  196. std::string &text = *_text;
  197. text += "{";
  198. int fieldout = 0;
  199. StructDef *union_sd = nullptr;
  200. for (auto it = struct_def.fields.vec.begin();
  201. it != struct_def.fields.vec.end();
  202. ++it) {
  203. FieldDef &fd = **it;
  204. if (struct_def.fixed || table->CheckField(fd.value.offset)) {
  205. // The field is present.
  206. if (fieldout++) {
  207. text += ",";
  208. }
  209. text += NewLine(opts);
  210. text.append(indent + Indent(opts), ' ');
  211. OutputIdentifier(fd.name, opts, _text);
  212. text += ": ";
  213. switch (fd.value.type.base_type) {
  214. #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
  215. case BASE_TYPE_ ## ENUM: \
  216. GenField<CTYPE>(fd, table, struct_def.fixed, \
  217. opts, indent + Indent(opts), _text); \
  218. break;
  219. FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
  220. #undef FLATBUFFERS_TD
  221. // Generate drop-thru case statements for all pointer types:
  222. #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE) \
  223. case BASE_TYPE_ ## ENUM:
  224. FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
  225. #undef FLATBUFFERS_TD
  226. GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
  227. union_sd, opts, _text);
  228. break;
  229. }
  230. if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
  231. auto enum_val = fd.value.type.enum_def->ReverseLookup(
  232. table->GetField<uint8_t>(fd.value.offset, 0));
  233. assert(enum_val);
  234. union_sd = enum_val->struct_def;
  235. }
  236. }
  237. }
  238. text += NewLine(opts);
  239. text.append(indent, ' ');
  240. text += "}";
  241. }
  242. // Generate a text representation of a flatbuffer in JSON format.
  243. void GenerateText(const Parser &parser, const void *flatbuffer,
  244. const GeneratorOptions &opts, std::string *_text) {
  245. std::string &text = *_text;
  246. assert(parser.root_struct_def); // call SetRootType()
  247. text.reserve(1024); // Reduce amount of inevitable reallocs.
  248. GenStruct(*parser.root_struct_def,
  249. GetRoot<Table>(flatbuffer),
  250. 0,
  251. opts,
  252. _text);
  253. text += NewLine(opts);
  254. }
  255. } // namespace flatbuffers