Added a "strict JSON" mode to the text generator and compiler

This will add quotes around field names, as required by the official
standard. By default it will leave quotes out, as it is more readable,
more compact, and is accepted by almost all JSON parsers.
The -S switch to flatc turns on strict mode.

As per rfc 7159.

Change-Id: Ibabe9c8162c47339d00ec581d18721a2ba40c6d0
Tested: on Windows.
This commit is contained in:
Wouter van Oortmerssen
2014-07-08 16:35:14 -07:00
parent 9140144d51
commit 7fcbe723fc
11 changed files with 94 additions and 50 deletions

View File

@@ -23,7 +23,8 @@
namespace flatbuffers {
static void GenStruct(const StructDef &struct_def, const Table *table,
int indent, int indent_step, std::string *_text);
int indent, const GeneratorOptions &opts,
std::string *_text);
// If indentation is less than 0, that indicates we don't want any newlines
// either.
@@ -35,7 +36,8 @@ const char *NewLine(int indent_step) {
// for a single FlatBuffer value into JSON format.
// The general case for scalars:
template<typename T> void Print(T val, Type /*type*/, int /*indent*/,
int /*indent_step*/, StructDef * /*union_sd*/,
StructDef * /*union_sd*/,
const GeneratorOptions & /*opts*/,
std::string *_text) {
std::string &text = *_text;
text += NumToString(val);
@@ -43,24 +45,25 @@ template<typename T> void Print(T val, Type /*type*/, int /*indent*/,
// Print a vector a sequence of JSON values, comma separated, wrapped in "[]".
template<typename T> void PrintVector(const Vector<T> &v, Type type,
int indent, int indent_step,
int indent, const GeneratorOptions &opts,
std::string *_text) {
std::string &text = *_text;
text += "[";
text += NewLine(indent_step);
text += NewLine(opts.indent_step);
for (uoffset_t i = 0; i < v.Length(); i++) {
if (i) {
text += ",";
text += NewLine(indent_step);
text += NewLine(opts.indent_step);
}
text.append(indent + indent_step, ' ');
text.append(indent + opts.indent_step, ' ');
if (IsStruct(type))
Print(v.GetStructFromOffset(i * type.struct_def->bytesize), type,
indent + indent_step, indent_step, nullptr, _text);
indent + opts.indent_step, nullptr, opts, _text);
else
Print(v.Get(i), type, indent + indent_step, indent_step, nullptr, _text);
Print(v.Get(i), type, indent + opts.indent_step, nullptr,
opts, _text);
}
text += NewLine(indent_step);
text += NewLine(opts.indent_step);
text.append(indent, ' ');
text += "]";
}
@@ -91,8 +94,10 @@ static void EscapeString(const String &s, std::string *_text) {
// Specialization of Print above for pointer types.
template<> void Print<const void *>(const void *val,
Type type, int indent, int indent_step,
StructDef *union_sd, std::string *_text) {
Type type, int indent,
StructDef *union_sd,
const GeneratorOptions &opts,
std::string *_text) {
switch (type.base_type) {
case BASE_TYPE_UNION:
// If this assert hits, you have an corrupt buffer, a union type field
@@ -101,14 +106,14 @@ template<> void Print<const void *>(const void *val,
GenStruct(*union_sd,
reinterpret_cast<const Table *>(val),
indent,
indent_step,
opts,
_text);
break;
case BASE_TYPE_STRUCT:
GenStruct(*type.struct_def,
reinterpret_cast<const Table *>(val),
indent,
indent_step,
opts,
_text);
break;
case BASE_TYPE_STRING: {
@@ -123,7 +128,7 @@ template<> void Print<const void *>(const void *val,
case BASE_TYPE_ ## ENUM: \
PrintVector<CTYPE>( \
*reinterpret_cast<const Vector<CTYPE> *>(val), \
type, indent, indent_step, _text); break;
type, indent, opts, _text); break;
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
}
@@ -135,18 +140,19 @@ template<> void Print<const void *>(const void *val,
// Generate text for a scalar field.
template<typename T> static void GenField(const FieldDef &fd,
const Table *table, bool fixed,
int indent_step, int indent,
const GeneratorOptions &opts,
int indent,
std::string *_text) {
Print(fixed ?
reinterpret_cast<const Struct *>(table)->GetField<T>(fd.value.offset) :
table->GetField<T>(fd.value.offset, 0), fd.value.type, indent, indent_step,
nullptr, _text);
table->GetField<T>(fd.value.offset, 0), fd.value.type, indent, nullptr,
opts, _text);
}
// Generate text for non-scalar field.
static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
int indent, int indent_step, StructDef *union_sd,
std::string *_text) {
int indent, StructDef *union_sd,
const GeneratorOptions &opts, std::string *_text) {
const void *val = nullptr;
if (fixed) {
// The only non-scalar fields in structs are structs.
@@ -158,16 +164,17 @@ static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
? table->GetStruct<const void *>(fd.value.offset)
: table->GetPointer<const void *>(fd.value.offset);
}
Print(val, fd.value.type, indent, indent_step, union_sd, _text);
Print(val, fd.value.type, indent, union_sd, opts, _text);
}
// Generate text for a struct or table, values separated by commas, indented,
// and bracketed by "{}"
static void GenStruct(const StructDef &struct_def, const Table *table,
int indent, int indent_step, std::string *_text) {
int indent, const GeneratorOptions &opts,
std::string *_text) {
std::string &text = *_text;
text += "{";
text += NewLine(indent_step);
text += NewLine(opts.indent_step);
int fieldout = 0;
StructDef *union_sd = nullptr;
for (auto it = struct_def.fields.vec.begin();
@@ -178,16 +185,18 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
// The field is present.
if (fieldout++) {
text += ",";
text += NewLine(indent_step);
text += NewLine(opts.indent_step);
}
text.append(indent + indent_step, ' ');
text.append(indent + opts.indent_step, ' ');
if (opts.strict_json) text += "\"";
text += fd.name;
if (opts.strict_json) text += "\"";
text += ": ";
switch (fd.value.type.base_type) {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE) \
case BASE_TYPE_ ## ENUM: \
GenField<CTYPE>(fd, table, struct_def.fixed, \
indent + indent_step, indent_step, _text); \
opts, indent + opts.indent_step, _text); \
break;
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
@@ -196,8 +205,8 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
case BASE_TYPE_ ## ENUM:
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
GenFieldOffset(fd, table, struct_def.fixed, indent + indent_step,
indent_step, union_sd, _text);
GenFieldOffset(fd, table, struct_def.fixed, indent + opts.indent_step,
union_sd, opts, _text);
break;
}
if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
@@ -206,23 +215,23 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
}
}
}
text += NewLine(indent_step);
text += NewLine(opts.indent_step);
text.append(indent, ' ');
text += "}";
}
// Generate a text representation of a flatbuffer in JSON format.
void GenerateText(const Parser &parser, const void *flatbuffer,
int indent_step, std::string *_text) {
const GeneratorOptions &opts, std::string *_text) {
std::string &text = *_text;
assert(parser.root_struct_def); // call SetRootType()
text.reserve(1024); // Reduce amount of inevitable reallocs.
GenStruct(*parser.root_struct_def,
GetRoot<Table>(flatbuffer),
0,
indent_step,
opts,
_text);
text += NewLine(indent_step);
text += NewLine(opts.indent_step);
}
} // namespace flatbuffers