summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWouter van Oortmerssen <aardappel@gmail.com>2017-01-18 12:02:31 -0800
committerWouter van Oortmerssen <aardappel@gmail.com>2017-01-18 14:54:16 -0800
commiteac2905568ec764f2d6fb0864ff95acec419d163 (patch)
treedebb9b4de2032052a8d6e937b14857011ccb03ba /src
parent19101826a80b415680738cf3722ee02a0b0c8565 (diff)
downloadflatbuffers-eac2905568ec764f2d6fb0864ff95acec419d163.tar.gz
flatbuffers-eac2905568ec764f2d6fb0864ff95acec419d163.tar.bz2
flatbuffers-eac2905568ec764f2d6fb0864ff95acec419d163.zip
Fixed unions not being parsed correctly in JSON.
This would happen if they were supplied in an order that does not match the schema relative to other fields. It now supports any ordering. Change-Id: I9d309cd4e6e5c470f01d9d431806eba4f9f46559 Tested: on Linux.
Diffstat (limited to 'src')
-rw-r--r--src/idl_parser.cpp25
1 files changed, 17 insertions, 8 deletions
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index e772f343..b514d94d 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -722,8 +722,17 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
case BASE_TYPE_UNION: {
assert(field);
std::string constant;
- if (!parent_fieldn ||
- field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE) {
+ // Find corresponding type field we may have already parsed.
+ for (auto elem = field_stack_.rbegin();
+ elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
+ auto &type = elem->second->value.type;
+ if (type.base_type == BASE_TYPE_UTYPE &&
+ type.enum_def == val.type.enum_def) {
+ constant = elem->first.constant;
+ break;
+ }
+ }
+ if (constant.empty()) {
// We haven't seen the type field yet. Sadly a lot of JSON writers
// output these in alphabetical order, meaning it comes after this
// value. So we scan past the value to find it, then come back here.
@@ -750,8 +759,6 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
constant = type_val.constant;
// Got the information we needed, now rewind:
*static_cast<ParserState *>(this) = backup;
- } else {
- constant = field_stack_.back().first.constant;
}
uint8_t enum_idx;
ECHECK(atot(constant.c_str(), *this, &enum_idx));
@@ -830,16 +837,18 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
} else {
Value val = field->value;
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
- size_t i = field_stack_.size();
// Hardcoded insertion-sort with error-check.
// If fields are specified in order, then this loop exits immediately.
- for (; i > field_stack_.size() - fieldn; i--) {
- auto existing_field = field_stack_[i - 1].second;
+ auto elem = field_stack_.rbegin();
+ for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
+ auto existing_field = elem->second;
if (existing_field == field)
return Error("field set more than once: " + field->name);
if (existing_field->value.offset < field->value.offset) break;
}
- field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field));
+ // Note: elem points to before the insertion point, thus .base() points
+ // to the correct spot.
+ field_stack_.insert(elem.base(), std::make_pair(val, field));
fieldn++;
}
}