Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2009 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/browser/extensions/extension_message_handler.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/hash_tables.h" | |
| 10 #include "base/scoped_ptr.h" | |
| 11 #include "base/string_util.h" | |
| 12 #include "base/values.h" | |
| 13 | |
| 14 const wchar_t* ExtensionMessageHandler::kContentKey = L"content"; | |
| 15 const wchar_t* ExtensionMessageHandler::kMessageKey = L"message"; | |
| 16 const wchar_t* ExtensionMessageHandler::kPlaceholdersKey = L"placeholders"; | |
| 17 | |
| 18 const char* ExtensionMessageHandler::kPlaceholderBegin = "$"; | |
| 19 const char* ExtensionMessageHandler::kPlaceholderEnd = "$"; | |
| 20 const char* ExtensionMessageHandler::kMessageBegin = "__MSG_"; | |
| 21 const char* ExtensionMessageHandler::kMessageEnd = "__"; | |
| 22 | |
| 23 // Formats message in case we encounter a bad formed key in the JSON object. | |
| 24 // Returns false and sets |error| to actual error message. | |
|
Aaron Boodman
2009/08/31 21:42:55
How about just returning the string since the retu
| |
| 25 static bool BadKeyMessage(const std::string& name, std::string* error) { | |
| 26 *error = StringPrintf("Name of a key \"%s\" is invalid. Only ASCII [a-z], " | |
| 27 "[A-Z], [0-9] and \"_\" are allowed.", name.c_str()); | |
| 28 return false; | |
| 29 } | |
| 30 | |
| 31 ExtensionMessageHandler::ExtensionMessageHandler() { | |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: Since the constructor and destructors are not
| |
| 32 } | |
| 33 | |
| 34 ExtensionMessageHandler::~ExtensionMessageHandler() { | |
| 35 } | |
| 36 | |
| 37 bool ExtensionMessageHandler::Init(const DictionaryValue* default_catalog, | |
|
Aaron Boodman
2009/08/31 21:42:55
The naming of these parameters is a bit confusing
| |
| 38 const DictionaryValue* app_catalog, | |
| 39 std::string* error) { | |
| 40 dictionary_.clear(); | |
| 41 | |
| 42 for (DictionaryValue::key_iterator key_it = app_catalog->begin_keys(); | |
| 43 key_it != app_catalog->end_keys(); | |
| 44 ++key_it) { | |
| 45 std::string key(WideToUTF8(*key_it)); | |
| 46 if (!IsValidName(key)) | |
| 47 return BadKeyMessage(key, error); | |
| 48 std::string value; | |
| 49 if (!GetMessageValue(*key_it, key, app_catalog, &value, error)) { | |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: braces unnecessary here.
| |
| 50 return false; | |
| 51 } | |
| 52 dictionary_.insert(make_pair(key, value)); | |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: I think the syntax dictionary[key] = value is
| |
| 53 } | |
| 54 | |
| 55 for (DictionaryValue::key_iterator key_it = default_catalog->begin_keys(); | |
| 56 key_it != default_catalog->end_keys(); | |
| 57 ++key_it) { | |
| 58 std::string key(WideToUTF8(*key_it)); | |
| 59 if (!IsValidName(key)) | |
| 60 return BadKeyMessage(key, error); | |
| 61 // Add only messages that are not provided by app_catalog. | |
| 62 if (dictionary_.find(key) != dictionary_.end()) | |
| 63 continue; | |
| 64 std::string value; | |
| 65 if (!GetMessageValue(*key_it, key, default_catalog, &value, error)) { | |
| 66 return false; | |
| 67 } | |
| 68 dictionary_.insert(make_pair(key, value)); | |
| 69 } | |
| 70 | |
| 71 return true; | |
| 72 } | |
| 73 | |
| 74 bool ExtensionMessageHandler::GetMessageValue( | |
| 75 const std::wstring& wkey, | |
| 76 const std::string& key, | |
| 77 const DictionaryValue* main_catalog, | |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: the "main_catalog" parameter seems misnamed.
| |
| 78 std::string* value, | |
| 79 std::string* error) const { | |
|
Aaron Boodman
2009/08/31 21:42:55
Add a DCHECK that the two keys are the same?
| |
| 80 // Get the top level tree for given key (name part). | |
| 81 DictionaryValue* name_tree; | |
| 82 if (!main_catalog->GetDictionary(wkey, &name_tree)) { | |
| 83 *error = StringPrintf("Not a valid tree for key %s.", key.c_str()); | |
| 84 return false; | |
| 85 } | |
| 86 // Extract message from it. | |
| 87 if (!name_tree->GetString(kMessageKey, value)) { | |
| 88 *error = StringPrintf("There is no \"%s\" element for key %s.", | |
| 89 WideToUTF8(kMessageKey).c_str(), | |
| 90 key.c_str()); | |
| 91 return false; | |
| 92 } | |
| 93 | |
| 94 SSMap placeholders; | |
| 95 if (!GetPlaceholders(name_tree, key, &placeholders, error)) { | |
| 96 return false; | |
| 97 } | |
| 98 if (!ReplacePlaceholdersInMessage(placeholders, value)) { | |
| 99 *error = StringPrintf("Placeholder \"%s\" is missing but used in a " | |
| 100 "message %s.", value->c_str(), key.c_str()); | |
| 101 return false; | |
| 102 } | |
| 103 | |
| 104 return true; | |
| 105 } | |
| 106 | |
| 107 bool ExtensionMessageHandler::GetPlaceholders(const DictionaryValue* name_tree, | |
| 108 const std::string name_key, | |
| 109 SSMap* placeholders, | |
| 110 std::string* error) const { | |
| 111 if (!name_tree->HasKey(kPlaceholdersKey)) | |
| 112 return true; | |
| 113 | |
| 114 DictionaryValue* placeholders_tree; | |
| 115 if (!name_tree->GetDictionary(kPlaceholdersKey, &placeholders_tree)) { | |
| 116 *error = StringPrintf("Not a valid \"%s\" element for key %s.", | |
| 117 WideToUTF8(kPlaceholdersKey).c_str(), | |
| 118 name_key.c_str()); | |
| 119 return false; | |
| 120 } | |
| 121 | |
| 122 for (DictionaryValue::key_iterator key_itr = placeholders_tree->begin_keys(); | |
| 123 key_itr != placeholders_tree->end_keys(); | |
| 124 ++key_itr) { | |
| 125 DictionaryValue* placeholder; | |
| 126 std::string content_key = WideToUTF8(*key_itr); | |
| 127 if (!IsValidName(content_key)) | |
| 128 return BadKeyMessage(content_key, error); | |
| 129 if (!placeholders_tree->GetDictionary(*key_itr, &placeholder)) { | |
| 130 *error = StringPrintf("Invalid placeholder %s for key %s", | |
| 131 content_key.c_str(), | |
| 132 name_key.c_str()); | |
| 133 return false; | |
| 134 } | |
| 135 std::string content; | |
| 136 if (!placeholder->GetString(kContentKey, &content)) { | |
| 137 *error = StringPrintf("Invalid \"%s\" element for key %s.", | |
| 138 WideToUTF8(kContentKey).c_str(), | |
| 139 name_key.c_str()); | |
| 140 return false; | |
| 141 } | |
| 142 placeholders->insert(std::make_pair(content_key, content)); | |
| 143 } | |
| 144 | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 bool ExtensionMessageHandler::ReplacePlaceholdersInMessage( | |
| 149 const SSMap& placeholders, | |
| 150 std::string* message) const { | |
| 151 return ReplaceVariablesInString( | |
| 152 placeholders, kPlaceholderBegin, kPlaceholderEnd, message); | |
| 153 } | |
| 154 | |
| 155 bool ExtensionMessageHandler::ReplaceMessagesInString(std::string* text) const { | |
| 156 return ReplaceVariablesInString( | |
| 157 dictionary_, kMessageBegin, kMessageEnd, text); | |
| 158 } | |
| 159 | |
| 160 bool ExtensionMessageHandler::ReplaceVariablesInString( | |
| 161 const SSMap& variables, | |
| 162 const std::string& var_begin, | |
| 163 const std::string& var_end, | |
| 164 std::string* message) const { | |
| 165 std::string::size_type beg_index = 0; | |
| 166 const std::string::size_type var_begin_size = var_begin.size(); | |
| 167 while (true) { | |
| 168 beg_index = message->find(var_begin, beg_index); | |
| 169 if (beg_index == message->npos) { | |
|
Aaron Boodman
2009/08/31 21:42:55
All these one line early exits can be braceless.
| |
| 170 return true; | |
| 171 } | |
| 172 // Advance it immediately to the begining of possible variable name. | |
| 173 beg_index += var_begin_size; | |
| 174 if (beg_index >= message->size()) { | |
| 175 return true; | |
| 176 } | |
| 177 std::string::size_type end_index = message->find(var_end, beg_index); | |
| 178 if (end_index == message->npos) { | |
| 179 return true; | |
| 180 } | |
| 181 // Looking for 1 in substring of ...$1$.... | |
| 182 const std::string& var_name = | |
| 183 message->substr(beg_index, end_index - beg_index); | |
| 184 if (!IsValidName(var_name)) { | |
| 185 continue; | |
| 186 } | |
| 187 SSMap::const_iterator it = variables.find(var_name); | |
| 188 if (it == variables.end()) { | |
| 189 message->assign(var_name); | |
|
Aaron Boodman
2009/08/31 21:42:55
Did you mean to replace the entire input string wi
| |
| 190 return false; | |
| 191 } | |
| 192 std::string value = it->second; | |
| 193 // Replace variable with its value. | |
| 194 message->replace(beg_index - var_begin_size, | |
| 195 end_index - beg_index + var_begin_size + var_end.size(), | |
| 196 value); | |
| 197 // And position pointer to after the replacement. | |
| 198 beg_index += value.size() - var_begin_size; | |
| 199 } | |
| 200 | |
| 201 return true; | |
| 202 } | |
| 203 | |
| 204 bool ExtensionMessageHandler::IsValidName(const std::string& name) const { | |
| 205 if (name.empty()) | |
| 206 return false; | |
| 207 | |
| 208 for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) { | |
| 209 // Allow only ascii 0-9, a-z, A-Z, and _ in the name. | |
| 210 if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it) && *it != '_') | |
| 211 return false; | |
| 212 } | |
| 213 | |
| 214 return true; | |
| 215 } | |
| 216 | |
| 217 // Dictionary interface. | |
| 218 | |
| 219 bool ExtensionMessageHandler::GetMessage(const std::string& name, | |
| 220 std::string* message) const { | |
| 221 SSMap::const_iterator it = dictionary_.find(name); | |
| 222 if (it != dictionary_.end()) { | |
| 223 message->assign(it->second); | |
| 224 return true; | |
| 225 } | |
| 226 | |
| 227 return false; | |
| 228 } | |
| OLD | NEW |