mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-23 05:00:01 +00:00
Added (nested) FlexBuffer JSON parsing and output.
FlexBuffer parser is just 40 lines of code (on top of existing parser!). Change-Id: Idebebadafb661ca5333f5621139031f6df3c3e1a Tested: on Linux.
This commit is contained in:
@@ -457,25 +457,61 @@ class Reference {
|
||||
}
|
||||
|
||||
// Unlike AsString(), this will convert any type to a std::string.
|
||||
std::string ToString() const {
|
||||
std::string ToString() {
|
||||
std::string s;
|
||||
ToString(false, false, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
// Convert any type to a JSON-like string. strings_quoted determines if
|
||||
// string values at the top level receive "" quotes (inside other values
|
||||
// they always do). keys_quoted determines if keys are quoted, at any level.
|
||||
// TODO(wvo): add further options to have indentation/newlines.
|
||||
void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const {
|
||||
if (type_ == TYPE_STRING) {
|
||||
return String(Indirect(), byte_width_).c_str();
|
||||
String str(Indirect(), byte_width_);
|
||||
if (strings_quoted) {
|
||||
flatbuffers::EscapeString(str.c_str(), str.length(), &s, true);
|
||||
} else {
|
||||
s.append(str.c_str(), str.length());
|
||||
}
|
||||
} else if (IsKey()) {
|
||||
return AsKey();
|
||||
auto str = AsKey();
|
||||
if (keys_quoted) {
|
||||
flatbuffers::EscapeString(str, strlen(str), &s, true);
|
||||
} else {
|
||||
s += str;
|
||||
}
|
||||
} else if (IsInt()) {
|
||||
return flatbuffers::NumToString(AsInt64());
|
||||
s += flatbuffers::NumToString(AsInt64());
|
||||
} else if (IsUInt()) {
|
||||
return flatbuffers::NumToString(AsUInt64());
|
||||
s += flatbuffers::NumToString(AsUInt64());
|
||||
} else if (IsFloat()) {
|
||||
return flatbuffers::NumToString(AsDouble());
|
||||
s += flatbuffers::NumToString(AsDouble());
|
||||
} else if (IsNull()) {
|
||||
return "null";
|
||||
s += "null";
|
||||
} else if (IsMap()) {
|
||||
return "{..}"; // TODO: show elements.
|
||||
s += "{ ";
|
||||
auto m = AsMap();
|
||||
auto keys = m.Keys();
|
||||
auto vals = m.Values();
|
||||
for (size_t i = 0; i < keys.size(); i++) {
|
||||
keys[i].ToString(true, keys_quoted, s);
|
||||
s += ": ";
|
||||
vals[i].ToString(true, keys_quoted, s);
|
||||
if (i < keys.size() - 1) s += ", ";
|
||||
}
|
||||
s += " }";
|
||||
} else if (IsVector()) {
|
||||
return "[..]"; // TODO: show elements.
|
||||
s += "[ ";
|
||||
auto v = AsVector();
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
v[i].ToString(true, keys_quoted, s);
|
||||
if (i < v.size() - 1) s += ", ";
|
||||
}
|
||||
s += " ]";
|
||||
} else {
|
||||
return "(?)";
|
||||
s += "(?)";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,6 +782,17 @@ class Builder FLATBUFFERS_FINAL_CLASS {
|
||||
return buf_;
|
||||
}
|
||||
|
||||
// Reset all state so we can re-use the buffer.
|
||||
void Clear() {
|
||||
buf_.clear();
|
||||
stack_.clear();
|
||||
finished_ = false;
|
||||
// flags_ remains as-is;
|
||||
force_min_bit_width_ = BIT_WIDTH_8;
|
||||
key_pool.clear();
|
||||
string_pool.clear();
|
||||
}
|
||||
|
||||
// All value constructing functions below have two versions: one that
|
||||
// takes a key (for placement inside a map) and one that doesn't (for inside
|
||||
// vectors and elsewhere).
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/hash.h"
|
||||
#include "flatbuffers/reflection.h"
|
||||
#include "flatbuffers/flexbuffers.h"
|
||||
|
||||
// This file defines the data types representing a parsed IDL (Interface
|
||||
// Definition Language) / schema file.
|
||||
@@ -226,18 +227,20 @@ struct Definition {
|
||||
};
|
||||
|
||||
struct FieldDef : public Definition {
|
||||
FieldDef() : deprecated(false), required(false), key(false), padding(0) {}
|
||||
FieldDef() : deprecated(false), required(false), key(false),
|
||||
flexbuffer(false), padding(0) {}
|
||||
|
||||
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
|
||||
const Parser &parser) const;
|
||||
|
||||
Value value;
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be.
|
||||
// written in new data nor accessed in new code.
|
||||
bool required; // Field must always be present.
|
||||
bool key; // Field functions as a key for creating sorted vectors.
|
||||
bool native_inline; // Field will be defined inline (instead of as a pointer)
|
||||
// for native tables if field is a struct.
|
||||
bool flexbuffer; // This field contains FlexBuffer data.
|
||||
size_t padding; // Bytes to always pad after this field.
|
||||
};
|
||||
|
||||
@@ -536,6 +539,11 @@ class Parser : public ParserState {
|
||||
// of the schema provided. Returns non-empty error on any problems.
|
||||
std::string ConformTo(const Parser &base);
|
||||
|
||||
// Similar to Parse(), but now only accepts JSON to be parsed into a
|
||||
// FlexBuffer.
|
||||
bool ParseFlexBuffer(const char *source, const char *source_filename,
|
||||
flexbuffers::Builder *builder);
|
||||
|
||||
FLATBUFFERS_CHECKED_ERROR CheckInRange(int64_t val, int64_t min, int64_t max);
|
||||
|
||||
private:
|
||||
@@ -559,15 +567,21 @@ private:
|
||||
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
|
||||
size_t parent_fieldn,
|
||||
const StructDef *parent_struct_def);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
const std::function<CheckedError(const std::string &name)> &body);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
|
||||
std::string *value, uoffset_t *ovalue);
|
||||
void SerializeStruct(const StructDef &struct_def, const Value &val);
|
||||
void AddVector(bool sortbysize, int count);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(size_t &count,
|
||||
const std::function<CheckedError()> &body);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes);
|
||||
FLATBUFFERS_CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e,
|
||||
BaseType req, bool *destmatch);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
|
||||
FLATBUFFERS_CHECKED_ERROR TokenError();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseSingleValue(Value &e);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
|
||||
StructDef *LookupCreateStruct(const std::string &name,
|
||||
@@ -587,9 +601,9 @@ private:
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type);
|
||||
FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonObject();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonArray();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonString();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
|
||||
FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
|
||||
const char *source_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
|
||||
const char **include_paths,
|
||||
const char *source_filename,
|
||||
|
||||
@@ -72,9 +72,8 @@ template<> inline std::string NumToString<double>(double t) {
|
||||
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
|
||||
auto p = s.find_last_not_of('0');
|
||||
if (p != std::string::npos) {
|
||||
s.resize(p + 1); // Strip trailing zeroes.
|
||||
if (s[s.size() - 1] == '.')
|
||||
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
|
||||
// Strip trailing zeroes. If it is a whole number, keep one zero.
|
||||
s.resize(p + (s[p] == '.' ? 2 : 1));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -361,6 +360,72 @@ inline std::string WordWrap(const std::string in, size_t max_length,
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
bool allow_non_utf8) {
|
||||
std::string &text = *_text;
|
||||
text += "\"";
|
||||
for (uoffset_t i = 0; i < length; i++) {
|
||||
char c = s[i];
|
||||
switch (c) {
|
||||
case '\n': text += "\\n"; break;
|
||||
case '\t': text += "\\t"; break;
|
||||
case '\r': text += "\\r"; break;
|
||||
case '\b': text += "\\b"; break;
|
||||
case '\f': text += "\\f"; break;
|
||||
case '\"': text += "\\\""; break;
|
||||
case '\\': text += "\\\\"; break;
|
||||
default:
|
||||
if (c >= ' ' && c <= '~') {
|
||||
text += c;
|
||||
} else {
|
||||
// Not printable ASCII data. Let's see if it's valid UTF-8 first:
|
||||
const char *utf8 = s + i;
|
||||
int ucc = FromUTF8(&utf8);
|
||||
if (ucc < 0) {
|
||||
if (allow_non_utf8) {
|
||||
text += "\\x";
|
||||
text += IntToStringHex(static_cast<uint8_t>(c), 2);
|
||||
} else {
|
||||
// There are two cases here:
|
||||
//
|
||||
// 1) We reached here by parsing an IDL file. In that case,
|
||||
// we previously checked for non-UTF-8, so we shouldn't reach
|
||||
// here.
|
||||
//
|
||||
// 2) We reached here by someone calling GenerateText()
|
||||
// on a previously-serialized flatbuffer. The data might have
|
||||
// non-UTF-8 Strings, or might be corrupt.
|
||||
//
|
||||
// In both cases, we have to give up and inform the caller
|
||||
// they have no JSON.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ucc <= 0xFFFF) {
|
||||
// Parses as Unicode within JSON's \uXXXX range, so use that.
|
||||
text += "\\u";
|
||||
text += IntToStringHex(ucc, 4);
|
||||
} else if (ucc <= 0x10FFFF) {
|
||||
// Encode Unicode SMP values to a surrogate pair using two \u escapes.
|
||||
uint32_t base = ucc - 0x10000;
|
||||
auto high_surrogate = (base >> 10) + 0xD800;
|
||||
auto low_surrogate = (base & 0x03FF) + 0xDC00;
|
||||
text += "\\u";
|
||||
text += IntToStringHex(high_surrogate, 4);
|
||||
text += "\\u";
|
||||
text += IntToStringHex(low_surrogate, 4);
|
||||
}
|
||||
// Skip past characters recognized.
|
||||
i = static_cast<uoffset_t>(utf8 - s - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
text += "\"";
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_UTIL_H_
|
||||
|
||||
Reference in New Issue
Block a user