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
= base::SplitString(
56 iter
.key(), ".", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
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
= base::JoinString(split
, ".");
67 if (root
.HasKey(parent_name
)) {
68 const base::DictionaryValue
* parent
= nullptr;
69 if (!root
.GetDictionaryWithoutPathExpansion(parent_name
, &parent
)) {
70 // If the parent is a complex feature, find the parent with the
71 // 'default_parent' flag.
72 const base::ListValue
* parent_list
= nullptr;
73 CHECK(root
.GetListWithoutPathExpansion(parent_name
, &parent_list
));
74 for (size_t i
= 0; i
< parent_list
->GetSize(); ++i
) {
75 CHECK(parent_list
->GetDictionary(i
, &parent
));
76 if (parent
->HasKey("default_parent"))
80 CHECK(parent
) << parent_name
<< " must declare one of its features"
81 << " the default parent, with {\"default_parent\": true}.";
83 parse_stack
.push(std::make_pair(parent_name
, parent
));
84 bool no_parent
= false;
85 parent
->GetBoolean("noparent", &no_parent
);
91 CHECK(!parse_stack
.empty());
92 // Parse all parent features.
93 bool parse_error
= false;
94 while (!parse_stack
.empty()) {
95 if (!ParseFeature(parse_stack
.top().second
,
96 parse_stack
.top().first
,
107 features_
[iter
.key()] = feature
;
108 } else if (iter
.value().GetType() == base::Value::TYPE_LIST
) {
109 // This is a complex feature.
110 const base::ListValue
* list
=
111 static_cast<const base::ListValue
*>(&iter
.value());
112 CHECK_GT(list
->GetSize(), 0UL);
114 scoped_ptr
<ComplexFeature::FeatureList
> features(
115 new ComplexFeature::FeatureList());
117 // Parse and add all SimpleFeatures from the list.
118 for (base::ListValue::const_iterator list_iter
= list
->begin();
119 list_iter
!= list
->end(); ++list_iter
) {
120 if ((*list_iter
)->GetType() != base::Value::TYPE_DICTIONARY
) {
121 LOG(ERROR
) << iter
.key() << ": Feature rules must be dictionaries.";
125 scoped_ptr
<SimpleFeature
> feature((*factory_
)());
126 if (!ParseFeature(static_cast<const base::DictionaryValue
*>(*list_iter
),
131 features
->push_back(feature
.Pass());
134 linked_ptr
<ComplexFeature
> feature(new ComplexFeature(features
.Pass()));
135 feature
->set_name(iter
.key());
137 features_
[iter
.key()] = feature
;
139 LOG(ERROR
) << iter
.key() << ": Feature description must be dictionary or"
140 << " list of dictionaries.";
145 BaseFeatureProvider::~BaseFeatureProvider() {
148 const std::vector
<std::string
>& BaseFeatureProvider::GetAllFeatureNames()
150 if (feature_names_
.empty()) {
151 for (FeatureMap::const_iterator iter
= features_
.begin();
152 iter
!= features_
.end(); ++iter
) {
153 feature_names_
.push_back(iter
->first
);
155 // A std::map is sorted by its keys, so we don't need to sort feature_names_
158 return feature_names_
;
161 Feature
* BaseFeatureProvider::GetFeature(const std::string
& name
) const {
162 FeatureMap::const_iterator iter
= features_
.find(name
);
163 if (iter
!= features_
.end())
164 return iter
->second
.get();
169 Feature
* BaseFeatureProvider::GetParent(Feature
* feature
) const {
171 if (feature
->no_parent())
174 std::vector
<std::string
> split
= base::SplitString(
175 feature
->name(), ".", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
176 if (split
.size() < 2)
179 return GetFeature(base::JoinString(split
, "."));
182 // Children of a given API are named starting with parent.name()+".", which
183 // means they'll be contiguous in the features_ std::map.
184 std::vector
<Feature
*> BaseFeatureProvider::GetChildren(const Feature
& parent
)
186 std::string prefix
= parent
.name() + ".";
187 const FeatureMap::const_iterator first_child
= features_
.lower_bound(prefix
);
189 // All children have names before (parent.name() + ('.'+1)).
190 ++prefix
[prefix
.size() - 1];
191 const FeatureMap::const_iterator after_children
=
192 features_
.lower_bound(prefix
);
194 std::vector
<Feature
*> result
;
195 result
.reserve(std::distance(first_child
, after_children
));
196 for (FeatureMap::const_iterator it
= first_child
; it
!= after_children
;
198 result
.push_back(it
->second
.get());
203 } // namespace extensions