|
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 |