From eac2905568ec764f2d6fb0864ff95acec419d163 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 18 Jan 2017 12:02:31 -0800 Subject: [PATCH] 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. --- src/idl_parser.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index e772f343a..b514d94d1 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(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++; } }