mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-08 06:05:17 +00:00
GenerateText gives text error on failure
This commit is contained in:
@@ -54,10 +54,10 @@ struct JsonPrinter {
|
||||
// for a single FlatBuffer value into JSON format.
|
||||
// The general case for scalars:
|
||||
template<typename T>
|
||||
bool PrintScalar(T val, const Type &type, int /*indent*/) {
|
||||
void PrintScalar(T val, const Type &type, int /*indent*/) {
|
||||
if (IsBool(type.base_type)) {
|
||||
text += val != 0 ? "true" : "false";
|
||||
return true; // done
|
||||
return; // done
|
||||
}
|
||||
|
||||
if (opts.output_enum_identifiers && type.enum_def) {
|
||||
@@ -66,7 +66,7 @@ struct JsonPrinter {
|
||||
text += '\"';
|
||||
text += ev->name;
|
||||
text += '\"';
|
||||
return true; // done
|
||||
return; // done
|
||||
} else if (val && enum_def.attributes.Lookup("bit_flags")) {
|
||||
const auto entry_len = text.length();
|
||||
const auto u64 = static_cast<uint64_t>(val);
|
||||
@@ -84,7 +84,7 @@ struct JsonPrinter {
|
||||
// Don't slice if (u64 != mask)
|
||||
if (mask && (u64 == mask)) {
|
||||
text[text.length() - 1] = '\"';
|
||||
return true; // done
|
||||
return; // done
|
||||
}
|
||||
text.resize(entry_len); // restore
|
||||
}
|
||||
@@ -92,7 +92,7 @@ struct JsonPrinter {
|
||||
}
|
||||
|
||||
text += NumToString(val);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
void AddComma() {
|
||||
@@ -102,7 +102,7 @@ struct JsonPrinter {
|
||||
// Print a vector or an array of JSON values, comma seperated, wrapped in
|
||||
// "[]".
|
||||
template<typename Container>
|
||||
bool PrintContainer(PrintScalarTag, const Container &c, size_t size,
|
||||
const char *PrintContainer(PrintScalarTag, const Container &c, size_t size,
|
||||
const Type &type, int indent, const uint8_t *) {
|
||||
const auto elem_indent = indent + Indent();
|
||||
text += '[';
|
||||
@@ -113,18 +113,18 @@ struct JsonPrinter {
|
||||
AddNewLine();
|
||||
}
|
||||
AddIndent(elem_indent);
|
||||
if (!PrintScalar(c[i], type, elem_indent)) { return false; }
|
||||
PrintScalar(c[i], type, elem_indent);
|
||||
}
|
||||
AddNewLine();
|
||||
AddIndent(indent);
|
||||
text += ']';
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Print a vector or an array of JSON values, comma seperated, wrapped in
|
||||
// "[]".
|
||||
template<typename Container>
|
||||
bool PrintContainer(PrintPointerTag, const Container &c, size_t size,
|
||||
const char *PrintContainer(PrintPointerTag, const Container &c, size_t size,
|
||||
const Type &type, int indent, const uint8_t *prev_val) {
|
||||
const auto is_struct = IsStruct(type);
|
||||
const auto elem_indent = indent + Indent();
|
||||
@@ -139,19 +139,18 @@ struct JsonPrinter {
|
||||
auto ptr = is_struct ? reinterpret_cast<const void *>(
|
||||
c.Data() + type.struct_def->bytesize * i)
|
||||
: c[i];
|
||||
if (!PrintOffset(ptr, type, elem_indent, prev_val,
|
||||
static_cast<soffset_t>(i))) {
|
||||
return false;
|
||||
}
|
||||
auto err = PrintOffset(ptr, type, elem_indent, prev_val,
|
||||
static_cast<soffset_t>(i));
|
||||
if (err) return err;
|
||||
}
|
||||
AddNewLine();
|
||||
AddIndent(indent);
|
||||
text += ']';
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool PrintVector(const void *val, const Type &type, int indent,
|
||||
const char *PrintVector(const void *val, const Type &type, int indent,
|
||||
const uint8_t *prev_val) {
|
||||
typedef Vector<T> Container;
|
||||
typedef typename PrintTag<typename Container::return_type>::type tag;
|
||||
@@ -162,14 +161,15 @@ struct JsonPrinter {
|
||||
|
||||
// Print an array a sequence of JSON values, comma separated, wrapped in "[]".
|
||||
template<typename T>
|
||||
bool PrintArray(const void *val, size_t size, const Type &type, int indent) {
|
||||
const char *PrintArray(const void *val, size_t size, const Type &type,
|
||||
int indent) {
|
||||
typedef Array<T, 0xFFFF> Container;
|
||||
typedef typename PrintTag<typename Container::return_type>::type tag;
|
||||
auto &arr = *reinterpret_cast<const Container *>(val);
|
||||
return PrintContainer<Container>(tag(), arr, size, type, indent, nullptr);
|
||||
}
|
||||
|
||||
bool PrintOffset(const void *val, const Type &type, int indent,
|
||||
const char *PrintOffset(const void *val, const Type &type, int indent,
|
||||
const uint8_t *prev_val, soffset_t vector_index) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_UNION: {
|
||||
@@ -186,7 +186,7 @@ struct JsonPrinter {
|
||||
if (enum_val) {
|
||||
return PrintOffset(val, enum_val->union_type, indent, nullptr, -1);
|
||||
} else {
|
||||
return false;
|
||||
return "unknown enum value";
|
||||
}
|
||||
}
|
||||
case BASE_TYPE_STRUCT:
|
||||
@@ -194,8 +194,9 @@ struct JsonPrinter {
|
||||
indent);
|
||||
case BASE_TYPE_STRING: {
|
||||
auto s = reinterpret_cast<const String *>(val);
|
||||
return EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8,
|
||||
opts.natural_utf8);
|
||||
bool ok = EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8,
|
||||
opts.natural_utf8);
|
||||
return ok ? nullptr : "string contains non-utf8 bytes";
|
||||
}
|
||||
case BASE_TYPE_VECTOR: {
|
||||
const auto vec_type = type.VectorType();
|
||||
@@ -203,17 +204,15 @@ struct JsonPrinter {
|
||||
// clang-format off
|
||||
switch (vec_type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
if (!PrintVector<CTYPE>( \
|
||||
val, vec_type, indent, prev_val)) { \
|
||||
return false; \
|
||||
} \
|
||||
break;
|
||||
case BASE_TYPE_ ## ENUM: { \
|
||||
auto err = PrintVector<CTYPE>(val, vec_type, indent, prev_val); \
|
||||
if (err) return err; \
|
||||
break; }
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
}
|
||||
// clang-format on
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
case BASE_TYPE_ARRAY: {
|
||||
const auto vec_type = type.VectorType();
|
||||
@@ -221,12 +220,10 @@ struct JsonPrinter {
|
||||
// clang-format off
|
||||
switch (vec_type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
if (!PrintArray<CTYPE>( \
|
||||
val, type.fixed_length, vec_type, indent)) { \
|
||||
return false; \
|
||||
} \
|
||||
break;
|
||||
case BASE_TYPE_ ## ENUM: { \
|
||||
auto err = PrintArray<CTYPE>(val, type.fixed_length, vec_type, indent); \
|
||||
if (err) return err; \
|
||||
break; }
|
||||
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
|
||||
// Arrays of scalars or structs are only possible.
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
|
||||
@@ -234,9 +231,11 @@ struct JsonPrinter {
|
||||
case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0);
|
||||
}
|
||||
// clang-format on
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
default: FLATBUFFERS_ASSERT(0); return false;
|
||||
default:
|
||||
FLATBUFFERS_ASSERT(0);
|
||||
return "unknown type";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,29 +249,28 @@ struct JsonPrinter {
|
||||
|
||||
// Generate text for a scalar field.
|
||||
template<typename T>
|
||||
bool GenField(const FieldDef &fd, const Table *table, bool fixed,
|
||||
void GenField(const FieldDef &fd, const Table *table, bool fixed,
|
||||
int indent) {
|
||||
if (fixed) {
|
||||
return PrintScalar(
|
||||
PrintScalar(
|
||||
reinterpret_cast<const Struct *>(table)->GetField<T>(fd.value.offset),
|
||||
fd.value.type, indent);
|
||||
} else if (fd.IsOptional()) {
|
||||
auto opt = table->GetOptional<T, T>(fd.value.offset);
|
||||
if (opt) {
|
||||
return PrintScalar(*opt, fd.value.type, indent);
|
||||
PrintScalar(*opt, fd.value.type, indent);
|
||||
} else {
|
||||
text += "null";
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return PrintScalar(
|
||||
PrintScalar(
|
||||
table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)),
|
||||
fd.value.type, indent);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate text for non-scalar field.
|
||||
bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
const char *GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
int indent, const uint8_t *prev_val) {
|
||||
const void *val = nullptr;
|
||||
if (fixed) {
|
||||
@@ -290,7 +288,7 @@ struct JsonPrinter {
|
||||
auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
|
||||
auto root = flexbuffers::GetRoot(vec->data(), vec->size());
|
||||
root.ToString(true, opts.strict_json, text);
|
||||
return true;
|
||||
return nullptr;
|
||||
} else if (fd.nested_flatbuffer && opts.json_nested_flatbuffers) {
|
||||
auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
|
||||
auto root = GetRoot<Table>(vec->data());
|
||||
@@ -305,7 +303,8 @@ struct JsonPrinter {
|
||||
|
||||
// Generate text for a struct or table, values separated by commas, indented,
|
||||
// and bracketed by "{}"
|
||||
bool GenStruct(const StructDef &struct_def, const Table *table, int indent) {
|
||||
const char *GenStruct(const StructDef &struct_def, const Table *table,
|
||||
int indent) {
|
||||
text += '{';
|
||||
int fieldout = 0;
|
||||
const uint8_t *prev_val = nullptr;
|
||||
@@ -329,11 +328,9 @@ struct JsonPrinter {
|
||||
// clang-format off
|
||||
switch (fd.value.type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
if (!GenField<CTYPE>(fd, table, struct_def.fixed, elem_indent)) { \
|
||||
return false; \
|
||||
} \
|
||||
break;
|
||||
case BASE_TYPE_ ## ENUM: { \
|
||||
GenField<CTYPE>(fd, table, struct_def.fixed, elem_indent); \
|
||||
break; }
|
||||
FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
// Generate drop-thru case statements for all pointer types:
|
||||
@@ -342,10 +339,11 @@ struct JsonPrinter {
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
|
||||
FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
if (!GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
{
|
||||
auto err = GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val);
|
||||
if (err) return err;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
// Track prev val for use with union types.
|
||||
@@ -359,7 +357,7 @@ struct JsonPrinter {
|
||||
AddNewLine();
|
||||
AddIndent(indent);
|
||||
text += '}';
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JsonPrinter(const Parser &parser, std::string &dest)
|
||||
@@ -371,16 +369,17 @@ struct JsonPrinter {
|
||||
std::string &text;
|
||||
};
|
||||
|
||||
static bool GenerateTextImpl(const Parser &parser, const Table *table,
|
||||
const StructDef &struct_def, std::string *_text) {
|
||||
static const char *GenerateTextImpl(const Parser &parser, const Table *table,
|
||||
const StructDef &struct_def, std::string *_text) {
|
||||
JsonPrinter printer(parser, *_text);
|
||||
if (!printer.GenStruct(struct_def, table, 0)) { return false; }
|
||||
auto err = printer.GenStruct(struct_def, table, 0);
|
||||
if (err) return err;
|
||||
printer.AddNewLine();
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Generate a text representation of a flatbuffer in JSON format.
|
||||
bool GenerateTextFromTable(const Parser &parser, const void *table,
|
||||
const char *GenerateTextFromTable(const Parser &parser, const void *table,
|
||||
const std::string &table_name, std::string *_text) {
|
||||
auto struct_def = parser.LookupStruct(table_name);
|
||||
if (struct_def == nullptr) { return false; }
|
||||
@@ -389,7 +388,7 @@ bool GenerateTextFromTable(const Parser &parser, const void *table,
|
||||
}
|
||||
|
||||
// Generate a text representation of a flatbuffer in JSON format.
|
||||
bool GenerateText(const Parser &parser, const void *flatbuffer,
|
||||
const char *GenerateText(const Parser &parser, const void *flatbuffer,
|
||||
std::string *_text) {
|
||||
FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType()
|
||||
auto root = parser.opts.size_prefixed ? GetSizePrefixedRoot<Table>(flatbuffer)
|
||||
@@ -402,21 +401,24 @@ static std::string TextFileName(const std::string &path,
|
||||
return path + file_name + ".json";
|
||||
}
|
||||
|
||||
bool GenerateTextFile(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
const char *GenerateTextFile(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
if (parser.opts.use_flexbuffers) {
|
||||
std::string json;
|
||||
parser.flex_root_.ToString(true, parser.opts.strict_json, json);
|
||||
return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
|
||||
json.c_str(), json.size(), true);
|
||||
json.c_str(), json.size(), true)
|
||||
? nullptr
|
||||
: "SaveFile failed";
|
||||
}
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return nullptr;
|
||||
std::string text;
|
||||
if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
|
||||
return false;
|
||||
}
|
||||
auto err = GenerateText(parser, parser.builder_.GetBufferPointer(), &text);
|
||||
if (err) return err;
|
||||
return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text,
|
||||
false);
|
||||
false)
|
||||
? nullptr
|
||||
: "SaveFile failed";
|
||||
}
|
||||
|
||||
std::string TextMakeRule(const Parser &parser, const std::string &path,
|
||||
@@ -439,7 +441,11 @@ class TextCodeGenerator : public CodeGenerator {
|
||||
public:
|
||||
Status GenerateCode(const Parser &parser, const std::string &path,
|
||||
const std::string &filename) override {
|
||||
if (!GenerateTextFile(parser, path, filename)) { return Status::ERROR; }
|
||||
auto err = GenerateTextFile(parser, path, filename);
|
||||
if (err) {
|
||||
status_detail = " (" + std::string(err) + ")";
|
||||
return Status::ERROR;
|
||||
}
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user