OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome_frame/simple_resource_loader.h" | 5 #include "chrome_frame/simple_resource_loader.h" |
6 | 6 |
7 #include <atlbase.h> | 7 #include <atlbase.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 | 10 |
11 #include "base/base_paths.h" | 11 #include "base/base_paths.h" |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
14 #include "base/path_service.h" | 14 #include "base/path_service.h" |
15 #include "base/i18n/rtl.h" | 15 #include "base/i18n/rtl.h" |
16 #include "base/memory/singleton.h" | 16 #include "base/memory/singleton.h" |
17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
18 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
19 #include "base/win/i18n.h" | 19 #include "base/win/i18n.h" |
20 #include "base/win/windows_version.h" | 20 #include "base/win/windows_version.h" |
21 | |
22 #include "chrome_frame/policy_settings.h" | 21 #include "chrome_frame/policy_settings.h" |
| 22 #include "ui/base/resource/data_pack.h" |
| 23 #include "ui/base/resource/resource_bundle.h" |
23 | 24 |
24 namespace { | 25 namespace { |
25 | 26 |
26 const wchar_t kLocalesDirName[] = L"Locales"; | 27 const wchar_t kLocalesDirName[] = L"Locales"; |
27 | 28 |
28 bool IsInvalidTagCharacter(wchar_t tag_character) { | 29 bool IsInvalidTagCharacter(wchar_t tag_character) { |
29 return !(L'-' == tag_character || | 30 return !(L'-' == tag_character || |
30 IsAsciiDigit(tag_character) || | 31 IsAsciiDigit(tag_character) || |
31 IsAsciiAlpha(tag_character)); | 32 IsAsciiAlpha(tag_character)); |
32 } | 33 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 if (0 < dash_pos && language.size() - 1 > dash_pos) | 77 if (0 < dash_pos && language.size() - 1 > dash_pos) |
77 modified |= PushBackIfAbsent(language.substr(0, dash_pos), collection); | 78 modified |= PushBackIfAbsent(language.substr(0, dash_pos), collection); |
78 } | 79 } |
79 | 80 |
80 return modified; | 81 return modified; |
81 } | 82 } |
82 | 83 |
83 } // namespace | 84 } // namespace |
84 | 85 |
85 SimpleResourceLoader::SimpleResourceLoader() | 86 SimpleResourceLoader::SimpleResourceLoader() |
86 : locale_dll_handle_(NULL) { | 87 : data_pack_(NULL), |
| 88 locale_dll_handle_(NULL) { |
87 // Find and load the resource DLL. | 89 // Find and load the resource DLL. |
88 std::vector<std::wstring> language_tags; | 90 std::vector<std::wstring> language_tags; |
89 | 91 |
90 // First, try the locale dictated by policy and its fallback. | 92 // First, try the locale dictated by policy and its fallback. |
91 PushBackWithFallbackIfAbsent( | 93 PushBackWithFallbackIfAbsent( |
92 PolicySettings::GetInstance()->ApplicationLocale(), | 94 PolicySettings::GetInstance()->ApplicationLocale(), |
93 &language_tags); | 95 &language_tags); |
94 | 96 |
95 // Next, try the thread, process, user, system languages. | 97 // Next, try the thread, process, user, system languages. |
96 GetPreferredLanguages(&language_tags); | 98 GetPreferredLanguages(&language_tags); |
97 | 99 |
98 // Finally, fall-back on "en-US" (which may already be present in the vector, | 100 // Finally, fall-back on "en-US" (which may already be present in the vector, |
99 // but that's okay since we'll exit with success when the first is tried). | 101 // but that's okay since we'll exit with success when the first is tried). |
100 language_tags.push_back(L"en-US"); | 102 language_tags.push_back(L"en-US"); |
101 | 103 |
102 FilePath locales_path; | 104 FilePath locales_path; |
103 FilePath locale_dll_path; | |
104 | 105 |
105 DetermineLocalesDirectory(&locales_path); | 106 DetermineLocalesDirectory(&locales_path); |
106 if (LoadLocaleDll(language_tags, locales_path, &locale_dll_handle_, | 107 if (!LoadLocalePack(language_tags, locales_path, &locale_dll_handle_, |
107 &locale_dll_path)) { | 108 &data_pack_, &language_)) { |
108 language_ = locale_dll_path.BaseName().RemoveExtension().value(); | |
109 } else { | |
110 NOTREACHED() << "Failed loading any resource dll (even \"en-US\")."; | 109 NOTREACHED() << "Failed loading any resource dll (even \"en-US\")."; |
111 } | 110 } |
112 } | 111 } |
113 | 112 |
114 SimpleResourceLoader::~SimpleResourceLoader() { | 113 SimpleResourceLoader::~SimpleResourceLoader() { |
115 locale_dll_handle_ = NULL; | 114 delete data_pack_; |
116 } | 115 } |
117 | 116 |
118 // static | 117 // static |
119 SimpleResourceLoader* SimpleResourceLoader::GetInstance() { | 118 SimpleResourceLoader* SimpleResourceLoader::GetInstance() { |
120 return Singleton<SimpleResourceLoader>::get(); | 119 return Singleton<SimpleResourceLoader>::get(); |
121 } | 120 } |
122 | 121 |
123 // static | 122 // static |
124 void SimpleResourceLoader::GetPreferredLanguages( | 123 void SimpleResourceLoader::GetPreferredLanguages( |
125 std::vector<std::wstring>* language_tags) { | 124 std::vector<std::wstring>* language_tags) { |
126 DCHECK(language_tags); | 125 DCHECK(language_tags); |
127 // The full set of preferred languages and their fallbacks are given priority. | 126 // The full set of preferred languages and their fallbacks are given priority. |
128 std::vector<std::wstring> languages; | 127 std::vector<std::wstring> languages; |
129 if (base::win::i18n::GetThreadPreferredUILanguageList(&languages)) { | 128 if (base::win::i18n::GetThreadPreferredUILanguageList(&languages)) { |
130 for (std::vector<std::wstring>::const_iterator scan = languages.begin(), | 129 for (std::vector<std::wstring>::const_iterator scan = languages.begin(), |
131 end = languages.end(); scan != end; ++scan) { | 130 end = languages.end(); scan != end; ++scan) { |
132 PushBackIfAbsent(*scan, language_tags); | 131 PushBackIfAbsent(*scan, language_tags); |
133 } | 132 } |
134 } | 133 } |
135 | |
136 // Use the base i18n routines (i.e., ICU) as a last, best hope for something | 134 // Use the base i18n routines (i.e., ICU) as a last, best hope for something |
137 // meaningful for the user. | 135 // meaningful for the user. |
138 PushBackWithFallbackIfAbsent(ASCIIToWide(base::i18n::GetConfiguredLocale()), | 136 PushBackWithFallbackIfAbsent(ASCIIToWide(base::i18n::GetConfiguredLocale()), |
139 language_tags); | 137 language_tags); |
140 } | 138 } |
141 | 139 |
142 // static | 140 // static |
143 void SimpleResourceLoader::DetermineLocalesDirectory(FilePath* locales_path) { | 141 void SimpleResourceLoader::DetermineLocalesDirectory(FilePath* locales_path) { |
144 DCHECK(locales_path); | 142 DCHECK(locales_path); |
145 | 143 |
(...skipping 19 matching lines...) Expand all Loading... |
165 // "[a-zA-Z]+(-[a-zA-Z0-9]+)*" is a simplification, but better than nothing. | 163 // "[a-zA-Z]+(-[a-zA-Z0-9]+)*" is a simplification, but better than nothing. |
166 // Rather than pick up the weight of a regex processor, just search for a | 164 // Rather than pick up the weight of a regex processor, just search for a |
167 // character that isn't in the above set. This will at least weed out | 165 // character that isn't in the above set. This will at least weed out |
168 // attempts at "../../EvilBinary". | 166 // attempts at "../../EvilBinary". |
169 return language_tag.end() == std::find_if(language_tag.begin(), | 167 return language_tag.end() == std::find_if(language_tag.begin(), |
170 language_tag.end(), | 168 language_tag.end(), |
171 &IsInvalidTagCharacter); | 169 &IsInvalidTagCharacter); |
172 } | 170 } |
173 | 171 |
174 // static | 172 // static |
175 bool SimpleResourceLoader::LoadLocaleDll( | 173 bool SimpleResourceLoader::LoadLocalePack( |
176 const std::vector<std::wstring>& language_tags, | 174 const std::vector<std::wstring>& language_tags, |
177 const FilePath& locales_path, | 175 const FilePath& locales_path, |
178 HMODULE* dll_handle, | 176 HMODULE* dll_handle, |
179 FilePath* file_path) { | 177 ui::DataPack** data_pack, |
180 DCHECK(file_path); | 178 std::wstring* language) { |
| 179 DCHECK(language); |
181 | 180 |
182 // The dll should only have resources, not executable code. | 181 // The dll should only have resources, not executable code. |
183 const DWORD load_flags = | 182 const DWORD load_flags = |
184 (base::win::GetVersion() >= base::win::VERSION_VISTA ? | 183 (base::win::GetVersion() >= base::win::VERSION_VISTA ? |
185 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE : | 184 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE : |
186 DONT_RESOLVE_DLL_REFERENCES); | 185 DONT_RESOLVE_DLL_REFERENCES); |
| 186 |
187 const std::wstring dll_suffix(L".dll"); | 187 const std::wstring dll_suffix(L".dll"); |
188 bool found_dll = false; | 188 const std::wstring pack_suffix(L".pak"); |
| 189 |
| 190 bool found_pack = false; |
189 | 191 |
190 for (std::vector<std::wstring>::const_iterator scan = language_tags.begin(), | 192 for (std::vector<std::wstring>::const_iterator scan = language_tags.begin(), |
191 end = language_tags.end(); | 193 end = language_tags.end(); |
192 scan != end; | 194 scan != end; |
193 ++scan) { | 195 ++scan) { |
194 if (!IsValidLanguageTag(*scan)) { | 196 if (!IsValidLanguageTag(*scan)) { |
195 LOG(WARNING) << "Invalid language tag supplied while locating resources:" | 197 LOG(WARNING) << "Invalid language tag supplied while locating resources:" |
196 " \"" << *scan << "\""; | 198 " \"" << *scan << "\""; |
197 continue; | 199 continue; |
198 } | 200 } |
199 FilePath look_path = locales_path.Append(*scan + dll_suffix); | 201 |
200 HMODULE locale_dll_handle = LoadLibraryEx(look_path.value().c_str(), NULL, | 202 // Attempt to load both the resource pack and the dll. We return success |
201 load_flags); | 203 // only we load both. |
202 if (NULL != locale_dll_handle) { | 204 FilePath resource_pack_path = locales_path.Append(*scan + pack_suffix); |
203 *dll_handle = locale_dll_handle; | 205 FilePath dll_path = locales_path.Append(*scan + dll_suffix); |
204 *file_path = look_path; | 206 |
205 found_dll = true; | 207 if (file_util::PathExists(resource_pack_path) && |
206 break; | 208 file_util::PathExists(dll_path)) { |
| 209 *data_pack = ui::ResourceBundle::LoadResourcesDataPak(resource_pack_path); |
| 210 if (!*data_pack) { |
| 211 continue; |
| 212 } |
| 213 HMODULE locale_dll_handle = LoadLibraryEx(dll_path.value().c_str(), NULL, |
| 214 load_flags); |
| 215 if (locale_dll_handle) { |
| 216 *dll_handle = locale_dll_handle; |
| 217 *language = dll_path.BaseName().RemoveExtension().value(); |
| 218 found_pack = true; |
| 219 break; |
| 220 } else { |
| 221 *data_pack = NULL; |
| 222 } |
207 } | 223 } |
208 DPCHECK(ERROR_FILE_NOT_FOUND == GetLastError()) | |
209 << "Unable to load generated resources from " << look_path.value(); | |
210 } | 224 } |
211 | 225 DCHECK(found_pack || file_util::DirectoryExists(locales_path)) |
212 DCHECK(found_dll || file_util::DirectoryExists(locales_path)) | |
213 << "Could not locate locales DLL directory."; | 226 << "Could not locate locales DLL directory."; |
214 | 227 return found_pack; |
215 return found_dll; | |
216 } | 228 } |
217 | 229 |
218 std::wstring SimpleResourceLoader::GetLocalizedResource(int message_id) { | 230 std::wstring SimpleResourceLoader::GetLocalizedResource(int message_id) { |
219 if (!locale_dll_handle_) { | 231 if (!data_pack_) { |
220 DLOG(ERROR) << "locale resources are not loaded"; | 232 DLOG(ERROR) << "locale resources are not loaded"; |
221 return std::wstring(); | 233 return std::wstring(); |
222 } | 234 } |
223 | 235 |
224 DCHECK(IS_INTRESOURCE(message_id)); | 236 DCHECK(IS_INTRESOURCE(message_id)); |
225 | 237 |
226 const ATLSTRINGRESOURCEIMAGE* image = AtlGetStringResourceImage( | 238 base::StringPiece data; |
227 locale_dll_handle_, message_id); | 239 if (!data_pack_->GetStringPiece(message_id, &data)) { |
228 if (!image) { | 240 DLOG(ERROR) << "Unable to find string for resource id:" << message_id; |
229 // Fall back on the current module (shouldn't be any strings here except | 241 return std::wstring(); |
230 // in unittests). | |
231 image = AtlGetStringResourceImage(_AtlBaseModule.GetModuleInstance(), | |
232 message_id); | |
233 if (!image) { | |
234 NOTREACHED() << "unable to find resource: " << message_id; | |
235 return std::wstring(); | |
236 } | |
237 } | 242 } |
238 return std::wstring(image->achString, image->nLength); | 243 |
| 244 // Data pack encodes strings as UTF16. |
| 245 DCHECK_EQ(data.length() % 2, 0U); |
| 246 string16 msg(reinterpret_cast<const char16*>(data.data()), |
| 247 data.length() / 2); |
| 248 return msg; |
239 } | 249 } |
240 | 250 |
241 // static | 251 // static |
242 std::wstring SimpleResourceLoader::GetLanguage() { | 252 std::wstring SimpleResourceLoader::GetLanguage() { |
243 return SimpleResourceLoader::GetInstance()->language_; | 253 return SimpleResourceLoader::GetInstance()->language_; |
244 } | 254 } |
245 | 255 |
246 // static | 256 // static |
247 std::wstring SimpleResourceLoader::Get(int message_id) { | 257 std::wstring SimpleResourceLoader::Get(int message_id) { |
248 SimpleResourceLoader* loader = SimpleResourceLoader::GetInstance(); | 258 SimpleResourceLoader* loader = SimpleResourceLoader::GetInstance(); |
249 return loader->GetLocalizedResource(message_id); | 259 return loader->GetLocalizedResource(message_id); |
250 } | 260 } |
251 | 261 |
252 HMODULE SimpleResourceLoader::GetResourceModuleHandle() { | 262 HMODULE SimpleResourceLoader::GetResourceModuleHandle() { |
253 return locale_dll_handle_; | 263 return locale_dll_handle_; |
254 } | 264 } |
OLD | NEW |