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 ParseFeature(const base::DictionaryValue
* value
,
21 const std::string
& name
,
22 SimpleFeature
* feature
) {
23 feature
->set_name(name
);
24 std::string error
= feature
->Parse(value
);
32 BaseFeatureProvider::BaseFeatureProvider(const base::DictionaryValue
& root
,
33 FeatureFactory factory
)
35 for (base::DictionaryValue::Iterator
iter(root
); !iter
.IsAtEnd();
37 if (iter
.value().GetType() == base::Value::TYPE_DICTIONARY
) {
38 linked_ptr
<SimpleFeature
> feature((*factory_
)());
40 std::vector
<std::string
> split
;
41 base::SplitString(iter
.key(), '.', &split
);
43 // Push parent features on the stack, starting with the current feature.
44 // If one of the features has "noparent" set, stop pushing features on
45 // the stack. The features will then be parsed in order, starting with
46 // the farthest parent that is either top level or has "noparent" set.
47 std::stack
<std::pair
<std::string
, const base::DictionaryValue
*> >
49 while (!split
.empty()) {
50 std::string parent_name
= JoinString(split
, '.');
52 if (root
.HasKey(parent_name
)) {
53 const base::DictionaryValue
* parent
= NULL
;
54 CHECK(root
.GetDictionaryWithoutPathExpansion(parent_name
, &parent
));
55 parse_stack
.push(std::make_pair(parent_name
, parent
));
56 bool no_parent
= false;
57 parent
->GetBoolean("noparent", &no_parent
);
63 CHECK(!parse_stack
.empty());
64 // Parse all parent features.
65 bool parse_error
= false;
66 while (!parse_stack
.empty()) {
67 if (!ParseFeature(parse_stack
.top().second
,
68 parse_stack
.top().first
,
79 features_
[iter
.key()] = feature
;
80 } else if (iter
.value().GetType() == base::Value::TYPE_LIST
) {
81 // This is a complex feature.
82 const base::ListValue
* list
=
83 static_cast<const base::ListValue
*>(&iter
.value());
84 CHECK_GT(list
->GetSize(), 0UL);
86 scoped_ptr
<ComplexFeature::FeatureList
> features(
87 new ComplexFeature::FeatureList());
89 // Parse and add all SimpleFeatures from the list.
90 for (base::ListValue::const_iterator list_iter
= list
->begin();
91 list_iter
!= list
->end(); ++list_iter
) {
92 if ((*list_iter
)->GetType() != base::Value::TYPE_DICTIONARY
) {
93 LOG(ERROR
) << iter
.key() << ": Feature rules must be dictionaries.";
97 scoped_ptr
<SimpleFeature
> feature((*factory_
)());
98 if (!ParseFeature(static_cast<const base::DictionaryValue
*>(*list_iter
),
103 features
->push_back(feature
.release());
106 linked_ptr
<ComplexFeature
> feature(new ComplexFeature(features
.Pass()));
107 feature
->set_name(iter
.key());
109 features_
[iter
.key()] = feature
;
111 LOG(ERROR
) << iter
.key() << ": Feature description must be dictionary or"
112 << " list of dictionaries.";
117 BaseFeatureProvider::~BaseFeatureProvider() {
120 const std::vector
<std::string
>& BaseFeatureProvider::GetAllFeatureNames()
122 if (feature_names_
.empty()) {
123 for (FeatureMap::const_iterator iter
= features_
.begin();
124 iter
!= features_
.end(); ++iter
) {
125 feature_names_
.push_back(iter
->first
);
127 // A std::map is sorted by its keys, so we don't need to sort feature_names_
130 return feature_names_
;
133 Feature
* BaseFeatureProvider::GetFeature(const std::string
& name
) const {
134 FeatureMap::const_iterator iter
= features_
.find(name
);
135 if (iter
!= features_
.end())
136 return iter
->second
.get();
141 Feature
* BaseFeatureProvider::GetParent(Feature
* feature
) const {
143 if (feature
->no_parent())
146 std::vector
<std::string
> split
;
147 base::SplitString(feature
->name(), '.', &split
);
148 if (split
.size() < 2)
151 return GetFeature(JoinString(split
, '.'));
154 // Children of a given API are named starting with parent.name()+".", which
155 // means they'll be contiguous in the features_ std::map.
156 std::vector
<Feature
*> BaseFeatureProvider::GetChildren(const Feature
& parent
)
158 std::string prefix
= parent
.name() + ".";
159 const FeatureMap::const_iterator first_child
= features_
.lower_bound(prefix
);
161 // All children have names before (parent.name() + ('.'+1)).
162 ++prefix
[prefix
.size() - 1];
163 const FeatureMap::const_iterator after_children
=
164 features_
.lower_bound(prefix
);
166 std::vector
<Feature
*> result
;
167 result
.reserve(std::distance(first_child
, after_children
));
168 for (FeatureMap::const_iterator it
= first_child
; it
!= after_children
;
170 result
.push_back(it
->second
.get());
175 } // namespace extensions