OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "extensions/common/api/declarative/declarative_manifest_data.h" | |
6 | |
7 #include "base/strings/stringprintf.h" | |
8 #include "base/strings/utf_string_conversions.h" | |
9 #include "extensions/common/manifest_constants.h" | |
10 | |
11 using base::UTF8ToUTF16; | |
12 using base::StringPrintf; | |
13 | |
14 namespace extensions { | |
15 | |
16 namespace { | |
17 | |
18 const char* ValueTypeToString(const base::Value* value) { | |
19 const base::Value::Type type = value->GetType(); | |
20 static const char* strings[] = {"null", | |
21 "boolean", | |
22 "integer", | |
23 "double", | |
24 "string", | |
25 "binary", | |
26 "dictionary", | |
27 "list"}; | |
28 CHECK(static_cast<size_t>(type) < arraysize(strings)); | |
29 return strings[type]; | |
30 } | |
31 | |
32 class ErrorBuilder { | |
33 public: | |
34 ErrorBuilder(base::string16* error) : error_(error) {} | |
not at google - send to devlin
2015/06/09 20:55:41
explicit
danduong
2015/06/10 00:17:16
Done.
| |
35 | |
36 // Appends a literal string |error|. | |
37 void Append(const char* error) { | |
38 if (error_->length()) | |
39 error_->append(UTF8ToUTF16("; ")); | |
40 error_->append(UTF8ToUTF16(error)); | |
41 } | |
42 | |
43 // Appends a string |error| with the first %s replaced by |sub|. | |
44 void Append(const char* error, const char* sub) { | |
45 Append(base::StringPrintf(error, sub).c_str()); | |
46 } | |
47 | |
48 private: | |
49 base::string16* error_; | |
50 DISALLOW_COPY_AND_ASSIGN(ErrorBuilder); | |
51 }; | |
52 | |
53 // Converts a rule defined in the manifest into a JSON internal format. The | |
54 // difference is that actions and conditions use a "type" key to define the | |
55 // type of rule/condition, while the internal format uses a "instanceType" key | |
56 // for this. This function walks through all the conditions and rules to swap | |
57 // the manifest key for the internal key. | |
58 bool ConvertManifestRule(const linked_ptr<DeclarativeManifestData::Rule>& rule, | |
59 ErrorBuilder* error_builder) { | |
60 auto convert_list = | |
61 [error_builder](std::vector<linked_ptr<base::Value>>& list) { | |
62 for (const linked_ptr<base::Value>& value : list) { | |
63 base::DictionaryValue* dictionary = nullptr; | |
64 if (!value->GetAsDictionary(&dictionary)) { | |
65 error_builder->Append("expected dictionary, got %s", | |
66 ValueTypeToString(value.get())); | |
67 return false; | |
68 } | |
69 std::string type; | |
70 if (!dictionary->GetString("type", &type)) { | |
71 error_builder->Append("'type' is required"); | |
not at google - send to devlin
2015/06/09 20:55:40
this will also fail if "type" is set but isn't a s
danduong
2015/06/10 00:17:16
Done.
| |
72 return false; | |
73 } | |
74 dictionary->Remove("type", nullptr); | |
75 dictionary->SetString("instanceType", type); | |
76 } | |
77 return true; | |
78 }; | |
79 return convert_list(rule->actions) && convert_list(rule->conditions); | |
80 } | |
81 | |
82 } // namespace | |
83 | |
84 DeclarativeManifestData::DeclarativeManifestData() { | |
85 } | |
86 | |
87 DeclarativeManifestData::~DeclarativeManifestData() { | |
88 } | |
89 | |
90 // static | |
91 DeclarativeManifestData* DeclarativeManifestData::Get( | |
92 const Extension* extension) { | |
93 return static_cast<DeclarativeManifestData*>( | |
94 extension->GetManifestData(manifest_keys::kEventRules)); | |
95 } | |
96 | |
97 // static | |
98 scoped_ptr<DeclarativeManifestData> DeclarativeManifestData::FromValue( | |
99 const base::Value& value, | |
100 base::string16* error) { | |
101 // The following is an example of how an event programmatic rule definition | |
102 // translates to a manifest definition. | |
103 // | |
104 // From javascript: | |
105 // | |
106 // chrome.declarativeContent.onPageChanged.addRules([{ | |
107 // actions: [ | |
108 // new chrome.declarativeContent.ShowPageAction() | |
109 // ], | |
110 // conditions: [ | |
111 // new chrome.declarativeContent.PageStateMatcher({css: ["video"]}) | |
112 // ] | |
113 // }]); | |
114 // | |
115 // In manifest: | |
116 // | |
117 // "event_rules": [{ | |
118 // "event" : "declarativeContent.onPageChanged", | |
119 // "actions" : [{ | |
120 // "type": "declarativeContent.ShowPageAction" | |
121 // }], | |
122 // "conditions" : [{ | |
123 // "css": ["video"], | |
124 // "type" : "declarativeContent.PageStateMatcher" | |
125 // }] | |
126 // }] | |
127 // | |
128 // The javascript objects get translated into JSON objects with a "type" | |
129 // field to indicate the instance type. Instead of adding rules to a | |
130 // specific event list, each rule has an "event" field to indicate which | |
131 // event it applies to. | |
132 // | |
133 ErrorBuilder error_builder(error); | |
134 scoped_ptr<DeclarativeManifestData> result(new DeclarativeManifestData()); | |
135 const base::ListValue* list = nullptr; | |
136 if (!value.GetAsList(&list)) { | |
137 error_builder.Append("'event_rules' expected list, got %s", | |
138 ValueTypeToString(&value)); | |
139 return scoped_ptr<DeclarativeManifestData>(); | |
140 } | |
141 | |
142 for (size_t i = 0; i < list->GetSize(); ++i) { | |
143 const base::DictionaryValue* dict = nullptr; | |
144 if (!list->GetDictionary(i, &dict)) { | |
145 const base::Value* value = nullptr; | |
146 if (list->Get(i, &value)) | |
147 error_builder.Append("expected dictionary, got %s", | |
148 ValueTypeToString(value)); | |
149 else | |
150 error_builder.Append("expected dictionary"); | |
151 return scoped_ptr<DeclarativeManifestData>(); | |
152 } | |
153 std::string event; | |
154 if (!dict->GetString("event", &event)) { | |
155 error_builder.Append("'event' is required"); | |
156 return scoped_ptr<DeclarativeManifestData>(); | |
157 } | |
158 | |
159 linked_ptr<Rule> rule(new Rule()); | |
160 if (Rule::Populate(*dict, rule.get()) && | |
161 ConvertManifestRule(rule, &error_builder)) { | |
162 result->event_rules_map_[event].push_back(rule); | |
163 } else { | |
164 error_builder.Append("rule failed to populate"); | |
not at google - send to devlin
2015/06/09 20:55:40
I think that, now, the Populate and the ConvertMan
| |
165 return scoped_ptr<DeclarativeManifestData>(); | |
166 } | |
167 } | |
168 return result.Pass(); | |
169 } | |
170 | |
171 std::vector<linked_ptr<DeclarativeManifestData::Rule>>& | |
172 DeclarativeManifestData::RulesForEvent(const std::string& event) { | |
173 return event_rules_map_[event]; | |
174 } | |
175 | |
176 } // namespace extensions | |
OLD | NEW |