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