123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- // Copyright 2018 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 "components/country_codes/country_codes.h"
- #include "build/build_config.h"
- #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
- #include <locale.h>
- #endif
- #include "base/strings/string_util.h"
- #include "build/build_config.h"
- #include "components/prefs/pref_registry_simple.h"
- #include "components/prefs/pref_service.h"
- #if BUILDFLAG(IS_WIN)
- #include <windows.h>
- #undef IN // On Windows, windef.h defines this, which screws up "India" cases.
- #elif BUILDFLAG(IS_APPLE)
- #include "base/mac/scoped_cftyperef.h"
- #endif
- #if BUILDFLAG(IS_ANDROID)
- #include "base/android/locale_utils.h"
- #endif
- namespace country_codes {
- namespace {
- // TODO(hcarmona/johntlee): remove this function after confirming if it only
- // pertains to obsolete OSes.
- int CountryCharsToCountryIDWithUpdate(char c1, char c2) {
- // SPECIAL CASE: In 2003, Yugoslavia renamed itself to Serbia and Montenegro.
- // Serbia and Montenegro dissolved their union in June 2006. Yugoslavia was
- // ISO 'YU' and Serbia and Montenegro were ISO 'CS'. Serbia was subsequently
- // issued 'RS' and Montenegro 'ME'. Windows XP and Mac OS X Leopard still use
- // the value 'YU'. If we get a value of 'YU' or 'CS' we will map it to 'RS'.
- if ((c1 == 'Y' && c2 == 'U') || (c1 == 'C' && c2 == 'S')) {
- c1 = 'R';
- c2 = 'S';
- }
- // SPECIAL CASE: Timor-Leste changed from 'TP' to 'TL' in 2002. Windows XP
- // predates this; we therefore map this value.
- if (c1 == 'T' && c2 == 'P')
- c2 = 'L';
- return CountryCharsToCountryID(c1, c2);
- }
- #if BUILDFLAG(IS_WIN)
- // For reference, a list of GeoIDs can be found at
- // http://msdn.microsoft.com/en-us/library/dd374073.aspx .
- int GeoIDToCountryID(GEOID geo_id) {
- const int kISOBufferSize = 3; // Two plus one for the terminator.
- wchar_t isobuf[kISOBufferSize] = {};
- int retval = GetGeoInfo(geo_id, GEO_ISO2, isobuf, kISOBufferSize, 0);
- if (retval == kISOBufferSize && !(isobuf[0] == L'X' && isobuf[1] == L'X')) {
- return CountryCharsToCountryIDWithUpdate(static_cast<char>(isobuf[0]),
- static_cast<char>(isobuf[1]));
- }
- // Various locations have ISO codes that Windows does not return.
- switch (geo_id) {
- case 0x144: // Guernsey
- return CountryCharsToCountryID('G', 'G');
- case 0x148: // Jersey
- return CountryCharsToCountryID('J', 'E');
- case 0x3B16: // Isle of Man
- return CountryCharsToCountryID('I', 'M');
- // 'UM' (U.S. Minor Outlying Islands)
- case 0x7F: // Johnston Atoll
- case 0x102: // Wake Island
- case 0x131: // Baker Island
- case 0x146: // Howland Island
- case 0x147: // Jarvis Island
- case 0x149: // Kingman Reef
- case 0x152: // Palmyra Atoll
- case 0x52FA: // Midway Islands
- return CountryCharsToCountryID('U', 'M');
- // 'SH' (Saint Helena)
- case 0x12F: // Ascension Island
- case 0x15C: // Tristan da Cunha
- return CountryCharsToCountryID('S', 'H');
- // 'IO' (British Indian Ocean Territory)
- case 0x13A: // Diego Garcia
- return CountryCharsToCountryID('I', 'O');
- // Other cases where there is no ISO country code; we assign countries that
- // can serve as reasonable defaults.
- case 0x154: // Rota Island
- case 0x155: // Saipan
- case 0x15A: // Tinian Island
- return CountryCharsToCountryID('U', 'S');
- case 0x134: // Channel Islands
- return CountryCharsToCountryID('G', 'B');
- case 0x143: // Guantanamo Bay
- default:
- return kCountryIDUnknown;
- }
- }
- #endif // BUILDFLAG(IS_WIN)
- } // namespace
- const char kCountryIDAtInstall[] = "countryid_at_install";
- int CountryStringToCountryID(const std::string& country) {
- return (country.length() == 2)
- ? CountryCharsToCountryIDWithUpdate(country[0], country[1])
- : kCountryIDUnknown;
- }
- int GetCountryIDFromPrefs(PrefService* prefs) {
- if (!prefs)
- return GetCurrentCountryID();
- // Cache first run Country ID value in prefs, and use it afterwards. This
- // ensures that just because the user moves around, we won't automatically
- // make major changes to their available search providers, which would feel
- // surprising.
- if (!prefs->HasPrefPath(country_codes::kCountryIDAtInstall)) {
- prefs->SetInteger(country_codes::kCountryIDAtInstall,
- GetCurrentCountryID());
- }
- return prefs->GetInteger(country_codes::kCountryIDAtInstall);
- }
- void RegisterProfilePrefs(PrefRegistrySimple* registry) {
- registry->RegisterIntegerPref(country_codes::kCountryIDAtInstall,
- kCountryIDUnknown);
- }
- #if BUILDFLAG(IS_WIN)
- int GetCurrentCountryID() {
- return GeoIDToCountryID(GetUserGeoID(GEOCLASS_NATION));
- }
- #elif BUILDFLAG(IS_APPLE)
- int GetCurrentCountryID() {
- base::ScopedCFTypeRef<CFLocaleRef> locale(CFLocaleCopyCurrent());
- CFStringRef country =
- (CFStringRef)CFLocaleGetValue(locale.get(), kCFLocaleCountryCode);
- if (!country)
- return kCountryIDUnknown;
- UniChar isobuf[2];
- CFRange char_range = CFRangeMake(0, 2);
- CFStringGetCharacters(country, char_range, isobuf);
- return CountryCharsToCountryIDWithUpdate(static_cast<char>(isobuf[0]),
- static_cast<char>(isobuf[1]));
- }
- #elif BUILDFLAG(IS_ANDROID)
- int GetCurrentCountryID() {
- return CountryStringToCountryID(base::android::GetDefaultCountryCode());
- }
- #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
- int GetCurrentCountryID() {
- const char* locale = setlocale(LC_MESSAGES, nullptr);
- if (!locale)
- return kCountryIDUnknown;
- // The format of a locale name is:
- // language[_territory][.codeset][@modifier], where territory is an ISO 3166
- // country code, which is what we want.
- // First remove the language portion.
- std::string locale_str(locale);
- size_t territory_delim = locale_str.find('_');
- if (territory_delim == std::string::npos)
- return kCountryIDUnknown;
- locale_str.erase(0, territory_delim + 1);
- // Next remove any codeset/modifier portion and uppercase.
- return CountryStringToCountryID(
- base::ToUpperASCII(locale_str.substr(0, locale_str.find_first_of(".@"))));
- }
- #endif // OS_*
- } // namespace country_codes
|