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 explicit ErrorBuilder(base::string16* error) : error_(error) {} |
| 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 and must be a string"); |
| 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 error_builder.Append("rule failed to populate"); |
| 162 return scoped_ptr<DeclarativeManifestData>(); |
| 163 } |
| 164 |
| 165 if (!ConvertManifestRule(rule, &error_builder)) |
| 166 return scoped_ptr<DeclarativeManifestData>(); |
| 167 |
| 168 result->event_rules_map_[event].push_back(rule); |
| 169 } |
| 170 return result.Pass(); |
| 171 } |
| 172 |
| 173 std::vector<linked_ptr<DeclarativeManifestData::Rule>>& |
| 174 DeclarativeManifestData::RulesForEvent(const std::string& event) { |
| 175 return event_rules_map_[event]; |
| 176 } |
| 177 |
| 178 } // namespace extensions |
OLD | NEW |