| 90 | }; |
| 91 | |
| 92 | void ConfigObject::ModifyAttribute(const String& attr, const Value& value, bool updateVersion) |
| 93 | { |
| 94 | Dictionary::Ptr original_attributes = GetOriginalAttributes(); |
| 95 | bool updated_original_attributes = false; |
| 96 | |
| 97 | Type::Ptr type = GetReflectionType(); |
| 98 | |
| 99 | std::vector<String> tokens = attr.Split("."); |
| 100 | |
| 101 | // This is reachable from ModifyObjectHandler. This check prevents API clients from creating deeply nested data |
| 102 | // structures that could overflow the stack later on. |
| 103 | if (tokens.size() > VarDepthLimit) { |
| 104 | BOOST_THROW_EXCEPTION(std::invalid_argument("Attribute '" + attr + "' exceeds maximum nesting level of " + |
| 105 | std::to_string(VarDepthLimit) + ".")); |
| 106 | } |
| 107 | |
| 108 | String fieldName = tokens[0]; |
| 109 | |
| 110 | int fid = type->GetFieldId(fieldName); |
| 111 | Field field = type->GetFieldInfo(fid); |
| 112 | |
| 113 | if (field.Attributes & FANoUserModify) |
| 114 | BOOST_THROW_EXCEPTION(std::invalid_argument("Attribute cannot be modified.")); |
| 115 | |
| 116 | if (field.Attributes & FAConfig) { |
| 117 | if (!original_attributes) { |
| 118 | original_attributes = new Dictionary(); |
| 119 | SetOriginalAttributes(original_attributes, true); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | Value oldValue = GetField(fid); |
| 124 | Value newValue; |
| 125 | |
| 126 | if (tokens.size() > 1) { |
| 127 | newValue = oldValue.Clone(); |
| 128 | Value current = newValue; |
| 129 | |
| 130 | if (current.IsEmpty()) { |
| 131 | current = new Dictionary(); |
| 132 | newValue = current; |
| 133 | } |
| 134 | |
| 135 | String prefix = tokens[0]; |
| 136 | |
| 137 | for (std::vector<String>::size_type i = 1; i < tokens.size() - 1; i++) { |
| 138 | if (!current.IsObjectType<Dictionary>()) |
| 139 | BOOST_THROW_EXCEPTION(std::invalid_argument("Value must be a dictionary.")); |
| 140 | |
| 141 | Dictionary::Ptr dict = current; |
| 142 | |
| 143 | const String& key = tokens[i]; |
| 144 | prefix += "." + key; |
| 145 | |
| 146 | if (!dict->Get(key, ¤t)) { |
| 147 | current = new Dictionary(); |
| 148 | dict->Set(key, current); |
| 149 | } |
no test coverage detected