1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/common/features/base_feature_provider.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "extensions/common/extensions_client.h"
13 #include "extensions/common/features/complex_feature.h"
14 #include "extensions/common/features/simple_feature.h"
16 namespace extensions
{
20 bool IsNocompile(const base::Value
& value
) {
21 bool nocompile
= false;
22 const base::DictionaryValue
* as_dict
= nullptr;
23 if (value
.GetAsDictionary(&as_dict
)) {
24 as_dict
->GetBoolean("nocompile", &nocompile
);
26 // "nocompile" is not supported for any other feature type.
31 bool ParseFeature(const base::DictionaryValue
* value
,
32 const std::string
& name
,
33 SimpleFeature
* feature
) {
34 feature
->set_name(name
);
35 std::string error
= feature
->Parse(value
);
43 BaseFeatureProvider::BaseFeatureProvider(const base::DictionaryValue
& root
,
44 FeatureFactory factory
)
46 for (base::DictionaryValue::Iterator
iter(root
); !iter
.IsAtEnd();
48 if (IsNocompile(iter
.value())) {
52 if (iter
.value().GetType() == base::Value::TYPE_DICTIONARY
) {
53 linked_ptr
<SimpleFeature
> feature((*factory_
)());
55 std::vector
<std::string
> split
;
56 base::SplitString(iter
.key(), '.', &split
);
58 // Push parent features on the stack, starting with the current feature.
59 // If one of the features has "noparent" set, stop pushing features on
60 // the stack. The features will then be parsed in order, starting with
61 // the farthest parent that is either top level or has "noparent" set.
62 std::stack
<std::pair
<std::string
, const base::DictionaryValue
*> >
64 while (!split
.empty()) {
65 std::string parent_name
= JoinString(split
, '.');
67 if (root
.HasKey(parent_name
)) {
68 const base::DictionaryValue
* parent
= nullptr;
69 CHECK(root
.GetDictionaryWithoutPathExpansion(parent_name
, &parent
));
70 parse_stack
.push(std::make_pair(parent_name
, parent
));
71 bool no_parent
= false;
72 parent
->GetBoolean("noparent", &no_parent
);
78 CHECK(!parse_stack
.empty());
79 // Parse all parent features.
80 bool parse_error
= false;
81 while (!parse_stack
.empty()) {
82 if (!ParseFeature(parse_stack
.top().second
,
83 parse_stack
.top().first
,
94 features_
[iter
.key()] = feature
;
95 } else if (iter
.value().GetType() == base::Value::TYPE_LIST
) {
96 // This is a complex feature.
97 const base::ListValue
* list
=
98 static_cast<const base::ListValue
*>(&iter
.value());
99 CHECK_GT(list
->GetSize(), 0UL);
101 scoped_ptr
<ComplexFeature::FeatureList
> features(
102 new ComplexFeature::FeatureList());
104 // Parse and add all SimpleFeatures from the list.
105 for (base::ListValue::const_iterator list_iter
= list
->begin();
106 list_iter
!= list
->end(); ++list_iter
) {
107 if ((*list_iter
)->GetType() != base::Value::TYPE_DICTIONARY
) {
108 LOG(ERROR
) << iter
.key() << ": Feature rules must be dictionaries.";
112 scoped_ptr
<SimpleFeature
> feature((*factory_
)());
113 if (!ParseFeature(static_cast<const base::DictionaryValue
*>(*list_iter
),
118 features
->push_back(feature
.release());
121 linked_ptr
<ComplexFeature
> feature(new ComplexFeature(features
.Pass()));
122 feature
->set_name(iter
.key());
124 features_
[iter
.key()] = feature
;
126 LOG(ERROR
) << iter
.key() << ": Feature description must be dictionary or"
127 << " list of dictionaries.";
132 BaseFeatureProvider::~BaseFeatureProvider() {
135 const std::vector
<std::string
>& BaseFeatureProvider::GetAllFeatureNames()
137 if (feature_names_
.empty()) {
138 for (FeatureMap::const_iterator iter
= features_
.begin();
139 iter
!= features_
.end(); ++iter
) {
140 feature_names_
.push_back(iter
->first
);
142 // A std::map is sorted by its keys, so we don't need to sort feature_names_
145 return feature_names_
;
148 Feature
* BaseFeatureProvider::GetFeature(const std::string
& name
) const {
149 FeatureMap::const_iterator iter
= features_
.find(name
);
150 if (iter
!= features_
.end())
151 return iter
->second
.get();
156 Feature
* BaseFeatureProvider::GetParent(Feature
* feature
) const {
158 if (feature
->no_parent())
161 std::vector
<std::string
> split
;
162 base::SplitString(feature
->name(), '.', &split
);
163 if (split
.size() < 2)
166 return GetFeature(JoinString(split
, '.'));
169 // Children of a given API are named starting with parent.name()+".", which
170 // means they'll be contiguous in the features_ std::map.
171 std::vector
<Feature
*> BaseFeatureProvider::GetChildren(const Feature
& parent
)
173 std::string prefix
= parent
.name() + ".";
174 const FeatureMap::const_iterator first_child
= features_
.lower_bound(prefix
);
176 // All children have names before (parent.name() + ('.'+1)).
177 ++prefix
[prefix
.size() - 1];
178 const FeatureMap::const_iterator after_children
=
179 features_
.lower_bound(prefix
);
181 std::vector
<Feature
*> result
;
182 result
.reserve(std::distance(first_child
, after_children
));
183 for (FeatureMap::const_iterator it
= first_child
; it
!= after_children
;
185 result
.push_back(it
->second
.get());
190 } // namespace extensions