Chromium Code Reviews| Index: chrome/browser/extensions/extension_message_handler.cc |
| =================================================================== |
| --- chrome/browser/extensions/extension_message_handler.cc (revision 0) |
| +++ chrome/browser/extensions/extension_message_handler.cc (revision 0) |
| @@ -0,0 +1,228 @@ |
| +// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/extensions/extension_message_handler.h" |
| + |
| +#include <string> |
| + |
| +#include "base/hash_tables.h" |
| +#include "base/scoped_ptr.h" |
| +#include "base/string_util.h" |
| +#include "base/values.h" |
| + |
| +const wchar_t* ExtensionMessageHandler::kContentKey = L"content"; |
| +const wchar_t* ExtensionMessageHandler::kMessageKey = L"message"; |
| +const wchar_t* ExtensionMessageHandler::kPlaceholdersKey = L"placeholders"; |
| + |
| +const char* ExtensionMessageHandler::kPlaceholderBegin = "$"; |
| +const char* ExtensionMessageHandler::kPlaceholderEnd = "$"; |
| +const char* ExtensionMessageHandler::kMessageBegin = "__MSG_"; |
| +const char* ExtensionMessageHandler::kMessageEnd = "__"; |
| + |
| +// Formats message in case we encounter a bad formed key in the JSON object. |
| +// 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
|
| +static bool BadKeyMessage(const std::string& name, std::string* error) { |
| + *error = StringPrintf("Name of a key \"%s\" is invalid. Only ASCII [a-z], " |
| + "[A-Z], [0-9] and \"_\" are allowed.", name.c_str()); |
| + return false; |
| +} |
| + |
| +ExtensionMessageHandler::ExtensionMessageHandler() { |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: Since the constructor and destructors are not
|
| +} |
| + |
| +ExtensionMessageHandler::~ExtensionMessageHandler() { |
| +} |
| + |
| +bool ExtensionMessageHandler::Init(const DictionaryValue* default_catalog, |
|
Aaron Boodman
2009/08/31 21:42:55
The naming of these parameters is a bit confusing
|
| + const DictionaryValue* app_catalog, |
| + std::string* error) { |
| + dictionary_.clear(); |
| + |
| + for (DictionaryValue::key_iterator key_it = app_catalog->begin_keys(); |
| + key_it != app_catalog->end_keys(); |
| + ++key_it) { |
| + std::string key(WideToUTF8(*key_it)); |
| + if (!IsValidName(key)) |
| + return BadKeyMessage(key, error); |
| + std::string value; |
| + if (!GetMessageValue(*key_it, key, app_catalog, &value, error)) { |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: braces unnecessary here.
|
| + return false; |
| + } |
| + dictionary_.insert(make_pair(key, value)); |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: I think the syntax dictionary[key] = value is
|
| + } |
| + |
| + for (DictionaryValue::key_iterator key_it = default_catalog->begin_keys(); |
| + key_it != default_catalog->end_keys(); |
| + ++key_it) { |
| + std::string key(WideToUTF8(*key_it)); |
| + if (!IsValidName(key)) |
| + return BadKeyMessage(key, error); |
| + // Add only messages that are not provided by app_catalog. |
| + if (dictionary_.find(key) != dictionary_.end()) |
| + continue; |
| + std::string value; |
| + if (!GetMessageValue(*key_it, key, default_catalog, &value, error)) { |
| + return false; |
| + } |
| + dictionary_.insert(make_pair(key, value)); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool ExtensionMessageHandler::GetMessageValue( |
| + const std::wstring& wkey, |
| + const std::string& key, |
| + const DictionaryValue* main_catalog, |
|
Aaron Boodman
2009/08/31 21:42:55
Nit: the "main_catalog" parameter seems misnamed.
|
| + std::string* value, |
| + std::string* error) const { |
|
Aaron Boodman
2009/08/31 21:42:55
Add a DCHECK that the two keys are the same?
|
| + // Get the top level tree for given key (name part). |
| + DictionaryValue* name_tree; |
| + if (!main_catalog->GetDictionary(wkey, &name_tree)) { |
| + *error = StringPrintf("Not a valid tree for key %s.", key.c_str()); |
| + return false; |
| + } |
| + // Extract message from it. |
| + if (!name_tree->GetString(kMessageKey, value)) { |
| + *error = StringPrintf("There is no \"%s\" element for key %s.", |
| + WideToUTF8(kMessageKey).c_str(), |
| + key.c_str()); |
| + return false; |
| + } |
| + |
| + SSMap placeholders; |
| + if (!GetPlaceholders(name_tree, key, &placeholders, error)) { |
| + return false; |
| + } |
| + if (!ReplacePlaceholdersInMessage(placeholders, value)) { |
| + *error = StringPrintf("Placeholder \"%s\" is missing but used in a " |
| + "message %s.", value->c_str(), key.c_str()); |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool ExtensionMessageHandler::GetPlaceholders(const DictionaryValue* name_tree, |
| + const std::string name_key, |
| + SSMap* placeholders, |
| + std::string* error) const { |
| + if (!name_tree->HasKey(kPlaceholdersKey)) |
| + return true; |
| + |
| + DictionaryValue* placeholders_tree; |
| + if (!name_tree->GetDictionary(kPlaceholdersKey, &placeholders_tree)) { |
| + *error = StringPrintf("Not a valid \"%s\" element for key %s.", |
| + WideToUTF8(kPlaceholdersKey).c_str(), |
| + name_key.c_str()); |
| + return false; |
| + } |
| + |
| + for (DictionaryValue::key_iterator key_itr = placeholders_tree->begin_keys(); |
| + key_itr != placeholders_tree->end_keys(); |
| + ++key_itr) { |
| + DictionaryValue* placeholder; |
| + std::string content_key = WideToUTF8(*key_itr); |
| + if (!IsValidName(content_key)) |
| + return BadKeyMessage(content_key, error); |
| + if (!placeholders_tree->GetDictionary(*key_itr, &placeholder)) { |
| + *error = StringPrintf("Invalid placeholder %s for key %s", |
| + content_key.c_str(), |
| + name_key.c_str()); |
| + return false; |
| + } |
| + std::string content; |
| + if (!placeholder->GetString(kContentKey, &content)) { |
| + *error = StringPrintf("Invalid \"%s\" element for key %s.", |
| + WideToUTF8(kContentKey).c_str(), |
| + name_key.c_str()); |
| + return false; |
| + } |
| + placeholders->insert(std::make_pair(content_key, content)); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool ExtensionMessageHandler::ReplacePlaceholdersInMessage( |
| + const SSMap& placeholders, |
| + std::string* message) const { |
| + return ReplaceVariablesInString( |
| + placeholders, kPlaceholderBegin, kPlaceholderEnd, message); |
| +} |
| + |
| +bool ExtensionMessageHandler::ReplaceMessagesInString(std::string* text) const { |
| + return ReplaceVariablesInString( |
| + dictionary_, kMessageBegin, kMessageEnd, text); |
| +} |
| + |
| +bool ExtensionMessageHandler::ReplaceVariablesInString( |
| + const SSMap& variables, |
| + const std::string& var_begin, |
| + const std::string& var_end, |
| + std::string* message) const { |
| + std::string::size_type beg_index = 0; |
| + const std::string::size_type var_begin_size = var_begin.size(); |
| + while (true) { |
| + beg_index = message->find(var_begin, beg_index); |
| + if (beg_index == message->npos) { |
|
Aaron Boodman
2009/08/31 21:42:55
All these one line early exits can be braceless.
|
| + return true; |
| + } |
| + // Advance it immediately to the begining of possible variable name. |
| + beg_index += var_begin_size; |
| + if (beg_index >= message->size()) { |
| + return true; |
| + } |
| + std::string::size_type end_index = message->find(var_end, beg_index); |
| + if (end_index == message->npos) { |
| + return true; |
| + } |
| + // Looking for 1 in substring of ...$1$.... |
| + const std::string& var_name = |
| + message->substr(beg_index, end_index - beg_index); |
| + if (!IsValidName(var_name)) { |
| + continue; |
| + } |
| + SSMap::const_iterator it = variables.find(var_name); |
| + if (it == variables.end()) { |
| + message->assign(var_name); |
|
Aaron Boodman
2009/08/31 21:42:55
Did you mean to replace the entire input string wi
|
| + return false; |
| + } |
| + std::string value = it->second; |
| + // Replace variable with its value. |
| + message->replace(beg_index - var_begin_size, |
| + end_index - beg_index + var_begin_size + var_end.size(), |
| + value); |
| + // And position pointer to after the replacement. |
| + beg_index += value.size() - var_begin_size; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool ExtensionMessageHandler::IsValidName(const std::string& name) const { |
| + if (name.empty()) |
| + return false; |
| + |
| + for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) { |
| + // Allow only ascii 0-9, a-z, A-Z, and _ in the name. |
| + if (!IsAsciiAlpha(*it) && !IsAsciiDigit(*it) && *it != '_') |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +// Dictionary interface. |
| + |
| +bool ExtensionMessageHandler::GetMessage(const std::string& name, |
| + std::string* message) const { |
| + SSMap::const_iterator it = dictionary_.find(name); |
| + if (it != dictionary_.end()) { |
| + message->assign(it->second); |
| + return true; |
| + } |
| + |
| + return false; |
| +} |
| Property changes on: chrome\browser\extensions\extension_message_handler.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |