summaryrefslogtreecommitdiffstats
path: root/chrome_frame/simple_resource_loader.cc
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 14:01:21 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 14:01:21 +0000
commit6ae3d4909757757f27940369e1bdc67eebd52b87 (patch)
treeb95726d81214d6824646008e53d870d0ee8f2feb /chrome_frame/simple_resource_loader.cc
parentb85e5120573c61b9bdd492fb903b334bf1119d8f (diff)
downloadchromium_src-6ae3d4909757757f27940369e1bdc67eebd52b87.zip
chromium_src-6ae3d4909757757f27940369e1bdc67eebd52b87.tar.gz
chromium_src-6ae3d4909757757f27940369e1bdc67eebd52b87.tar.bz2
Various changes to make GCF nicer for the non-en-US world:
- Chrome Frame now uses MUI on Vista+ to detect IE's UX language. - Chrome Frame now tells Chrome (via the --lang command-line option) what the current langauge is. - Chrome Frame now respects Chrome's "ApplicationLocaleValue" group policy setting. BUG=56435,59582 TEST=chrome_frame_unittests and chrome_frame_tests updated Review URL: http://codereview.chromium.org/3757007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63208 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame/simple_resource_loader.cc')
-rw-r--r--chrome_frame/simple_resource_loader.cc288
1 files changed, 214 insertions, 74 deletions
diff --git a/chrome_frame/simple_resource_loader.cc b/chrome_frame/simple_resource_loader.cc
index e39087c..844afa7 100644
--- a/chrome_frame/simple_resource_loader.cc
+++ b/chrome_frame/simple_resource_loader.cc
@@ -4,40 +4,174 @@
#include "chrome_frame/simple_resource_loader.h"
+#include <algorithm>
+
#include <atlbase.h>
-#include <string>
#include "base/base_paths.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/i18n/file_util_icu.h"
#include "base/i18n/rtl.h"
+#include "base/singleton.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/win/windows_version.h"
+#include "chrome_frame/policy_settings.h"
+
+namespace {
+
const wchar_t kLocalesDirName[] = L"Locales";
-HINSTANCE SimpleResourceLoader::locale_dll_handle_;
+bool IsInvalidTagCharacter(wchar_t tag_character) {
+ return !(L'-' == tag_character ||
+ IsAsciiDigit(tag_character) ||
+ IsAsciiAlpha(tag_character));
+}
+
+// A helper function object that performs a lower-case ASCII comparison between
+// two strings.
+class CompareInsensitiveASCII
+ : public std::unary_function<const std::wstring&, bool> {
+ public:
+ explicit CompareInsensitiveASCII(const std::wstring& value)
+ : value_lowered_(WideToASCII(value)) {
+ StringToLowerASCII(&value_lowered_);
+ }
+ bool operator()(const std::wstring& comparand) {
+ return LowerCaseEqualsASCII(comparand, value_lowered_.c_str());
+ }
+
+ private:
+ std::string value_lowered_;
+};
+
+// Returns true if the value was added.
+bool PushBackIfAbsent(
+ const std::wstring& value,
+ std::vector<std::wstring>* collection) {
+ if (collection->end() ==
+ std::find_if(collection->begin(), collection->end(),
+ CompareInsensitiveASCII(value))) {
+ collection->push_back(value);
+ return true;
+ }
+ return false;
+}
+
+} // namespace
-SimpleResourceLoader::SimpleResourceLoader() {
+SimpleResourceLoader::SimpleResourceLoader()
+ : locale_dll_handle_(NULL) {
// Find and load the resource DLL.
+ std::vector<std::wstring> language_tags;
+
+ // First, try the locale dictated by policy and its fallback.
+ std::wstring application_locale =
+ Singleton<PolicySettings>()->ApplicationLocale();
+ if (!application_locale.empty()) {
+ language_tags.push_back(application_locale);
+ std::wstring::size_type dash = application_locale.find(L'-');
+ if (std::wstring::npos != dash) {
+ if (0 != dash) {
+ language_tags.push_back(application_locale.substr(0, dash));
+ } else {
+ NOTREACHED() << "Group Policy application locale begins with a dash.";
+ }
+ }
+ }
+
+ // Next, try the thread, process, user, system languages.
+ GetPreferredLanguages(&language_tags);
+
+ // Finally, fall-back on "en-US" (which may already be present in the vector,
+ // but that's okay since we'll exit with success when the first is tried).
+ language_tags.push_back(L"en-US");
+
+ FilePath locales_path;
+ FilePath locale_dll_path;
+
+ DetermineLocalesDirectory(&locales_path);
+ if (LoadLocaleDll(language_tags, locales_path, &locale_dll_handle_,
+ &locale_dll_path)) {
+ language_ = locale_dll_path.BaseName().RemoveExtension().value();
+ } else {
+ NOTREACHED() << "Failed loading any resource dll (even \"en-US\").";
+ }
+}
+
+SimpleResourceLoader::~SimpleResourceLoader() {
+ locale_dll_handle_ = NULL;
+}
+
+// static
+void SimpleResourceLoader::GetPreferredLanguages(
+ std::vector<std::wstring>* language_tags) {
+ // The full set of preferred languages and their fallbacks are given priority.
+ GetThreadPreferredUILanguages(language_tags);
+
+ // The above gives us nothing pre-Vista, so use ICU to get the system
+ // language and add it and its fallback to the end of the list if not present.
std::wstring language;
std::wstring region;
- GetSystemLocale(&language, &region);
- FilePath locale_dll_path;
- if (GetLocaleFilePath(language, region, &locale_dll_path)) {
- DCHECK(locale_dll_handle_ == NULL) << "Locale DLL is already loaded!";
- locale_dll_handle_ = LoadLocaleDll(locale_dll_path);
- DCHECK(locale_dll_handle_ != NULL) << "Failed to load locale dll!";
+ GetICUSystemLanguage(&language, &region);
+ if (!region.empty()) {
+ std::wstring combined;
+ combined.reserve(language.size() + 1 + region.size());
+ combined.assign(language).append(L"-").append(region);
+ PushBackIfAbsent(combined, language_tags);
}
+ PushBackIfAbsent(language, language_tags);
}
-SimpleResourceLoader::~SimpleResourceLoader() {}
+// static
+bool SimpleResourceLoader::GetThreadPreferredUILanguages(
+ std::vector<std::wstring>* language_tags) {
+ typedef BOOL (WINAPI* GetThreadPreferredUILanguages_Fn)(
+ DWORD, PULONG, PZZWSTR, PULONG);
+ HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+ DCHECK(kernel32) << "Failed finding kernel32.dll!";
+ GetThreadPreferredUILanguages_Fn get_thread_preferred_ui_languages =
+ reinterpret_cast<GetThreadPreferredUILanguages_Fn>(
+ GetProcAddress(kernel32, "GetThreadPreferredUILanguages"));
+ bool have_mui = (NULL != get_thread_preferred_ui_languages);
+ if (have_mui) {
+ const DWORD kNameAndFallbackFlags =
+ MUI_LANGUAGE_NAME | MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK;
+ ULONG language_count = 0;
+ ULONG buffer_length = 0;
+
+ if (get_thread_preferred_ui_languages(
+ kNameAndFallbackFlags,
+ &language_count,
+ NULL,
+ &buffer_length) && 0 != buffer_length) {
+ std::vector<wchar_t> language_names(buffer_length);
+
+ if (get_thread_preferred_ui_languages(
+ kNameAndFallbackFlags,
+ &language_count,
+ &language_names[0],
+ &buffer_length)) {
+ std::vector<wchar_t>::const_iterator scan = language_names.begin();
+ std::wstring language(&*scan);
+ while (!language.empty()) {
+ language_tags->push_back(language);
+ scan += language.size() + 1;
+ language.assign(&*scan);
+ }
+ }
+ }
+ }
+ return have_mui;
+}
-void SimpleResourceLoader::GetSystemLocale(std::wstring* language,
- std::wstring* region) {
+// static
+void SimpleResourceLoader::GetICUSystemLanguage(std::wstring* language,
+ std::wstring* region) {
DCHECK(language);
DCHECK(region);
@@ -45,89 +179,90 @@ void SimpleResourceLoader::GetSystemLocale(std::wstring* language,
base::i18n::GetLanguageAndRegionFromOS(&icu_language, &icu_region);
if (!icu_language.empty()) {
*language = ASCIIToWide(icu_language);
+ } else {
+ language->clear();
}
if (!icu_region.empty()) {
*region = ASCIIToWide(icu_region);
+ } else {
+ region->clear();
}
}
-bool SimpleResourceLoader::GetLocaleFilePath(const std::wstring& language,
- const std::wstring& region,
- FilePath* file_path) {
- DCHECK(file_path);
+// static
+void SimpleResourceLoader::DetermineLocalesDirectory(FilePath* locales_path) {
+ DCHECK(locales_path);
FilePath module_path;
PathService::Get(base::DIR_MODULE, &module_path);
- FilePath locales_path = module_path.Append(kLocalesDirName);
+ *locales_path = module_path.Append(kLocalesDirName);
// We may be residing in the "locales" directory's parent, or we might be
// in a sibling directory. Move up one and look for Locales again in the
// latter case.
- if (!file_util::DirectoryExists(locales_path)) {
- locales_path = module_path.DirName();
- locales_path = locales_path.Append(kLocalesDirName);
+ if (!file_util::DirectoryExists(*locales_path)) {
+ *locales_path = module_path.DirName();
+ *locales_path = locales_path->Append(kLocalesDirName);
}
- bool found_dll = false;
- if (file_util::DirectoryExists(locales_path)) {
- std::wstring dll_name(language);
- FilePath look_path;
-
- // First look for the [language]-[region].DLL.
- if (!region.empty()) {
- dll_name += L"-";
- dll_name += region;
- dll_name += L".dll";
-
- look_path = locales_path.Append(dll_name);
- if (file_util::PathExists(look_path)) {
- *file_path = look_path;
- found_dll = true;
- }
- }
-
- // Next look for just [language].DLL.
- if (!found_dll) {
- dll_name = language;
- dll_name += L".dll";
- look_path = locales_path.Append(dll_name);
- if (file_util::PathExists(look_path)) {
- *file_path = look_path;
- found_dll = true;
- }
- }
-
- // Finally, try defaulting to en-US.dll.
- if (!found_dll) {
- look_path = locales_path.Append(L"en-US.dll");
- if (file_util::PathExists(look_path)) {
- *file_path = look_path;
- found_dll = true;
- }
- }
- } else {
- NOTREACHED() << "Could not locate locales DLL directory.";
- }
+ // Don't make a second check to see if the dir is in the parent. We'll notice
+ // and log that in LoadLocaleDll when we actually try loading DLLs.
+}
- return found_dll;
+// static
+bool SimpleResourceLoader::IsValidLanguageTag(
+ const std::wstring& language_tag) {
+ // "[a-zA-Z]+(-[a-zA-Z0-9]+)*" is a simplification, but better than nothing.
+ // Rather than pick up the weight of a regex processor, just search for a
+ // character that isn't in the above set. This will at least weed out
+ // attempts at "../../EvilBinary".
+ return language_tag.end() == std::find_if(language_tag.begin(),
+ language_tag.end(),
+ &IsInvalidTagCharacter);
}
-HINSTANCE SimpleResourceLoader::LoadLocaleDll(const FilePath& dll_path) {
- DWORD load_flags = 0;
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
- load_flags = LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE |
- LOAD_LIBRARY_AS_IMAGE_RESOURCE;
- } else {
- load_flags = DONT_RESOLVE_DLL_REFERENCES;
- }
+// static
+bool SimpleResourceLoader::LoadLocaleDll(
+ const std::vector<std::wstring>& language_tags,
+ const FilePath& locales_path,
+ HMODULE* dll_handle,
+ FilePath* file_path) {
+ DCHECK(file_path);
// The dll should only have resources, not executable code.
- HINSTANCE locale_dll_handle = LoadLibraryEx(dll_path.value().c_str(), NULL,
+ const DWORD load_flags =
+ (base::win::GetVersion() >= base::win::VERSION_VISTA ?
+ LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE :
+ DONT_RESOLVE_DLL_REFERENCES);
+ const std::wstring dll_suffix(L".dll");
+ bool found_dll = false;
+
+ for (std::vector<std::wstring>::const_iterator scan = language_tags.begin(),
+ end = language_tags.end();
+ scan != end;
+ ++scan) {
+ if (!IsValidLanguageTag(*scan)) {
+ LOG(WARNING) << "Invalid language tag supplied while locating resources:"
+ " \"" << *scan << "\"";
+ continue;
+ }
+ FilePath look_path = locales_path.Append(*scan + dll_suffix);
+ HMODULE locale_dll_handle = LoadLibraryEx(look_path.value().c_str(), NULL,
load_flags);
- DCHECK(locale_dll_handle != NULL) << "unable to load generated resources: "
- << GetLastError();
+ if (NULL != locale_dll_handle) {
+ *dll_handle = locale_dll_handle;
+ *file_path = look_path;
+ found_dll = true;
+ break;
+ }
+ DPCHECK(ERROR_FILE_NOT_FOUND == GetLastError())
+ << "Unable to load generated resources from " << look_path.value();
+ }
+
+ DCHECK(found_dll || file_util::DirectoryExists(locales_path))
+ << "Could not locate locales DLL directory.";
- return locale_dll_handle;
+ return found_dll;
}
std::wstring SimpleResourceLoader::GetLocalizedResource(int message_id) {
@@ -154,11 +289,16 @@ std::wstring SimpleResourceLoader::GetLocalizedResource(int message_id) {
}
// static
+std::wstring SimpleResourceLoader::GetLanguage() {
+ return SimpleResourceLoader::instance()->language_;
+}
+
+// static
std::wstring SimpleResourceLoader::Get(int message_id) {
SimpleResourceLoader* loader = SimpleResourceLoader::instance();
return loader->GetLocalizedResource(message_id);
}
-HINSTANCE SimpleResourceLoader::GetResourceModuleHandle() {
+HMODULE SimpleResourceLoader::GetResourceModuleHandle() {
return locale_dll_handle_;
}