Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: chrome/common/extensions/features/base_feature_provider.cc

Issue 224163002: Move core features code to //extensions (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: move tests Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "chrome/common/extensions/features/base_feature_provider.h"
6
7 #include <stack>
8
9 #include "base/json/json_reader.h"
10 #include "base/lazy_instance.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "chrome/common/extensions/features/api_feature.h"
14 #include "chrome/common/extensions/features/complex_feature.h"
15 #include "chrome/common/extensions/features/manifest_feature.h"
16 #include "chrome/common/extensions/features/permission_feature.h"
17 #include "extensions/common/extensions_client.h"
18 #include "grit/common_resources.h"
19 #include "ui/base/resource/resource_bundle.h"
20
21 namespace extensions {
22
23 namespace {
24
25 template<class FeatureClass>
26 SimpleFeature* CreateFeature() {
27 SimpleFeature* feature = new FeatureClass();
28 ExtensionsClient::Get()->AddExtraFeatureFilters(feature);
29 return feature;
30 }
31
32 static BaseFeatureProvider* LoadProvider(
33 const std::string& name,
34 BaseFeatureProvider::FeatureFactory factory,
35 int resource_id) {
36 const std::string& features_file =
37 ResourceBundle::GetSharedInstance().GetRawDataResource(
38 resource_id).as_string();
39 int error_code = 0;
40 std::string error_message;
41 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
42 features_file, base::JSON_PARSE_RFC,
43 &error_code, &error_message));
44 DCHECK(value) << "Could not load features: " << name << " "
45 << error_message;
46 scoped_ptr<base::DictionaryValue> value_as_dict;
47 if (value) {
48 CHECK(value->IsType(base::Value::TYPE_DICTIONARY)) << name;
49 value_as_dict.reset(static_cast<base::DictionaryValue*>(value.release()));
50 } else {
51 // http://crbug.com/176381
52 value_as_dict.reset(new base::DictionaryValue());
53 }
54 return new BaseFeatureProvider(*value_as_dict, factory);
55 }
56
57 struct Static {
58 Static() {
59 feature_providers["api"] = make_linked_ptr(
60 LoadProvider("api",
61 &CreateFeature<APIFeature>,
62 IDR_EXTENSION_API_FEATURES));
63 feature_providers["permission"] = make_linked_ptr(
64 LoadProvider("permission",
65 &CreateFeature<PermissionFeature>,
66 IDR_EXTENSION_PERMISSION_FEATURES));
67 feature_providers["manifest"] = make_linked_ptr(
68 LoadProvider("manifest",
69 &CreateFeature<ManifestFeature>,
70 IDR_EXTENSION_MANIFEST_FEATURES));
71 }
72
73 typedef std::map<std::string, linked_ptr<FeatureProvider> >
74 FeatureProviderMap;
75
76 FeatureProvider* GetFeatures(const std::string& name) const {
77 FeatureProviderMap::const_iterator it = feature_providers.find(name);
78 CHECK(it != feature_providers.end());
79 return it->second.get();
80 }
81
82 FeatureProviderMap feature_providers;
83 };
84
85 base::LazyInstance<Static> g_static = LAZY_INSTANCE_INITIALIZER;
86
87 bool ParseFeature(const base::DictionaryValue* value,
88 const std::string& name,
89 SimpleFeature* feature) {
90 feature->set_name(name);
91 std::string error = feature->Parse(value);
92 if (!error.empty())
93 LOG(ERROR) << error;
94 return error.empty();
95 }
96
97 } // namespace
98
99 BaseFeatureProvider::BaseFeatureProvider(const base::DictionaryValue& root,
100 FeatureFactory factory)
101 : factory_(factory ? factory :
102 static_cast<FeatureFactory>(&CreateFeature<SimpleFeature>)) {
103 for (base::DictionaryValue::Iterator iter(root); !iter.IsAtEnd();
104 iter.Advance()) {
105 if (iter.value().GetType() == base::Value::TYPE_DICTIONARY) {
106 linked_ptr<SimpleFeature> feature((*factory_)());
107
108 std::vector<std::string> split;
109 base::SplitString(iter.key(), '.', &split);
110
111 // Push parent features on the stack, starting with the current feature.
112 // If one of the features has "noparent" set, stop pushing features on
113 // the stack. The features will then be parsed in order, starting with
114 // the farthest parent that is either top level or has "noparent" set.
115 std::stack<std::pair<std::string, const base::DictionaryValue*> >
116 parse_stack;
117 while (!split.empty()) {
118 std::string parent_name = JoinString(split, '.');
119 split.pop_back();
120 if (root.HasKey(parent_name)) {
121 const base::DictionaryValue* parent = NULL;
122 CHECK(root.GetDictionaryWithoutPathExpansion(parent_name, &parent));
123 parse_stack.push(std::make_pair(parent_name, parent));
124 bool no_parent = false;
125 parent->GetBoolean("noparent", &no_parent);
126 if (no_parent)
127 break;
128 }
129 }
130
131 CHECK(!parse_stack.empty());
132 // Parse all parent features.
133 bool parse_error = false;
134 while (!parse_stack.empty()) {
135 if (!ParseFeature(parse_stack.top().second,
136 parse_stack.top().first,
137 feature.get())) {
138 parse_error = true;
139 break;
140 }
141 parse_stack.pop();
142 }
143
144 if (parse_error)
145 continue;
146
147 features_[iter.key()] = feature;
148 } else if (iter.value().GetType() == base::Value::TYPE_LIST) {
149 // This is a complex feature.
150 const base::ListValue* list =
151 static_cast<const base::ListValue*>(&iter.value());
152 CHECK_GT(list->GetSize(), 0UL);
153
154 scoped_ptr<ComplexFeature::FeatureList> features(
155 new ComplexFeature::FeatureList());
156
157 // Parse and add all SimpleFeatures from the list.
158 for (base::ListValue::const_iterator list_iter = list->begin();
159 list_iter != list->end(); ++list_iter) {
160 if ((*list_iter)->GetType() != base::Value::TYPE_DICTIONARY) {
161 LOG(ERROR) << iter.key() << ": Feature rules must be dictionaries.";
162 continue;
163 }
164
165 scoped_ptr<SimpleFeature> feature((*factory_)());
166 if (!ParseFeature(static_cast<const base::DictionaryValue*>(*list_iter),
167 iter.key(),
168 feature.get()))
169 continue;
170
171 features->push_back(feature.release());
172 }
173
174 linked_ptr<ComplexFeature> feature(new ComplexFeature(features.Pass()));
175 feature->set_name(iter.key());
176
177 features_[iter.key()] = feature;
178 } else {
179 LOG(ERROR) << iter.key() << ": Feature description must be dictionary or"
180 << " list of dictionaries.";
181 }
182 }
183 }
184
185 BaseFeatureProvider::~BaseFeatureProvider() {
186 }
187
188 // static
189 FeatureProvider* BaseFeatureProvider::GetByName(
190 const std::string& name) {
191 return g_static.Get().GetFeatures(name);
192 }
193
194 const std::vector<std::string>& BaseFeatureProvider::GetAllFeatureNames()
195 const {
196 if (feature_names_.empty()) {
197 for (FeatureMap::const_iterator iter = features_.begin();
198 iter != features_.end(); ++iter) {
199 feature_names_.push_back(iter->first);
200 }
201 // A std::map is sorted by its keys, so we don't need to sort feature_names_
202 // now.
203 }
204 return feature_names_;
205 }
206
207 Feature* BaseFeatureProvider::GetFeature(const std::string& name) const {
208 FeatureMap::const_iterator iter = features_.find(name);
209 if (iter != features_.end())
210 return iter->second.get();
211 else
212 return NULL;
213 }
214
215 Feature* BaseFeatureProvider::GetParent(Feature* feature) const {
216 CHECK(feature);
217 if (feature->no_parent())
218 return NULL;
219
220 std::vector<std::string> split;
221 base::SplitString(feature->name(), '.', &split);
222 if (split.size() < 2)
223 return NULL;
224 split.pop_back();
225 return GetFeature(JoinString(split, '.'));
226 }
227
228 // Children of a given API are named starting with parent.name()+".", which
229 // means they'll be contiguous in the features_ std::map.
230 std::vector<Feature*> BaseFeatureProvider::GetChildren(const Feature& parent)
231 const {
232 std::string prefix = parent.name() + ".";
233 const FeatureMap::const_iterator first_child = features_.lower_bound(prefix);
234
235 // All children have names before (parent.name() + ('.'+1)).
236 ++prefix[prefix.size() - 1];
237 const FeatureMap::const_iterator after_children =
238 features_.lower_bound(prefix);
239
240 std::vector<Feature*> result;
241 result.reserve(std::distance(first_child, after_children));
242 for (FeatureMap::const_iterator it = first_child; it != after_children;
243 ++it) {
244 result.push_back(it->second.get());
245 }
246 return result;
247 }
248
249 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698