blob: 02d5cd81a744af6c8df51f1a7e55f47ab82bf2b0 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// 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
#if BUILDFLAG(IS_APPLE)
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "base/strings/string_util.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/apple/scoped_cftyperef.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "base/android/locale_utils.h"
#endif
namespace country_codes {
namespace {
#if BUILDFLAG(IS_WIN)
// For reference, a list of GeoIDs can be found at
// http://msdn.microsoft.com/en-us/library/dd374073.aspx .
CountryId 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')) {
char code[2]{static_cast<char>(isobuf[0]), static_cast<char>(isobuf[1])};
return CountryId(std::string_view(code, std::size(code)));
}
// Various locations have ISO codes that Windows does not return.
switch (geo_id) {
case 0x144: // Guernsey
return CountryId("GG");
case 0x148: // Jersey
return CountryId("JE");
case 0x3B16: // Isle of Man
return CountryId("IM");
// '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 CountryId("UM");
// 'SH' (Saint Helena)
case 0x12F: // Ascension Island
case 0x15C: // Tristan da Cunha
return CountryId("SH");
// 'IO' (British Indian Ocean Territory)
case 0x13A: // Diego Garcia
return CountryId("IO");
// 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 CountryId("US");
case 0x134: // Channel Islands
return CountryId("GB");
case 0x143: // Guantanamo Bay
default:
return CountryId();
}
}
#endif // BUILDFLAG(IS_WIN)
} // namespace
#if BUILDFLAG(IS_WIN)
CountryId GetCurrentCountryID() {
// Calls to GetCurrentCountryID occur fairly frequently and incur a heavy
// registry hit within the GetUserGeoID api call. Registry hits can be
// impactful to perf, particularly on virtualized systems. To mitigate this
// we store the result of the first call in a static. The Id is only
// updated by calls to SetUserGeoID or the user manually updating the
// language and region settings. It is expected that if it changes the user
// would need to restart applications to ensure the updated value is
// respected.
static CountryId id = GeoIDToCountryID(GetUserGeoID(GEOCLASS_NATION));
return id;
}
#elif BUILDFLAG(IS_APPLE)
CountryId GetCurrentCountryID() {
base::apple::ScopedCFTypeRef<CFLocaleRef> locale(CFLocaleCopyCurrent());
CFStringRef country =
(CFStringRef)CFLocaleGetValue(locale.get(), kCFLocaleCountryCode);
if (!country) {
return CountryId();
}
UniChar isobuf[2];
CFRange char_range = CFRangeMake(0, 2);
CFStringGetCharacters(country, char_range, isobuf);
char code[2]{static_cast<char>(isobuf[0]), static_cast<char>(isobuf[1])};
return CountryId(std::string_view(code, std::size(code)));
}
#elif BUILDFLAG(IS_ANDROID)
CountryId GetCurrentCountryID() {
return CountryId(base::android::GetDefaultCountryCode());
}
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
CountryId GetCurrentCountryID() {
const char* locale = setlocale(LC_MESSAGES, nullptr);
if (!locale) {
return CountryId();
}
// 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 CountryId();
}
locale_str.erase(0, territory_delim + 1);
// Next remove any codeset/modifier portion and uppercase.
return CountryId(
base::ToUpperASCII(locale_str.substr(0, locale_str.find_first_of(".@"))));
}
#endif // OS_*
} // namespace country_codes