blob: 259ca65f76ab998f16a3d149541e6d6f517d1911 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <windows.h>
#include <string>
#include <string_view>
#include "base/strings/string_util.h"
#include "base/strings/string_util_win.h"
#include "content/browser/sandbox_support_impl.h"
namespace content {
namespace {
LCID CallLocaleNameToLCID(std::u16string_view locale) {
CHECK(locale.size() < LOCALE_NAME_MAX_LENGTH);
return ::LocaleNameToLCID(base::as_wcstr(locale), 0);
}
std::u16string GetLocaleInfoString(LCID lcid,
LCTYPE type,
bool force_defaults) {
if (force_defaults) {
type = type | LOCALE_NOUSEROVERRIDE;
}
int size_with_nul = ::GetLocaleInfo(lcid, type, 0, 0);
if (size_with_nul <= 0) {
return std::u16string();
}
std::u16string buffer;
// basic_string guarantees that `buffer` can be indexed from
// [0, size], with the requirement that buffer[size] is only set
// to NUL.
buffer.resize(size_with_nul - 1);
::GetLocaleInfo(lcid, type, base::as_writable_wcstr(buffer.data()),
size_with_nul);
return buffer;
}
std::vector<std::u16string> GetLocaleInfoStrings(LCID lcid,
base::span<const LCTYPE> types,
bool force_defaults,
bool allow_empty) {
std::vector<std::u16string> strings;
for (const auto& type : types) {
auto str = GetLocaleInfoString(lcid, type, force_defaults);
if (str.empty() && !allow_empty) {
return {};
}
strings.push_back(std::move(str));
}
return strings;
}
std::optional<DWORD> GetLocaleInfoDWORD(LCID lcid,
LCTYPE type,
bool force_defaults) {
DWORD result = 0;
if (force_defaults) {
type = type | LOCALE_NOUSEROVERRIDE;
}
if (::GetLocaleInfo(lcid, type | LOCALE_RETURN_NUMBER,
reinterpret_cast<LPWSTR>(&result),
sizeof(DWORD) / sizeof(TCHAR)) > 0) {
return result;
}
return std::nullopt;
}
std::u16string_view LanguageCode(const std::u16string_view locale) {
size_t dash_pos = locale.find('-');
if (dash_pos == std::u16string::npos) {
return locale;
}
return locale.substr(0, dash_pos);
}
LCID LCIDFromLocale(const std::u16string& locale, bool force_defaults) {
auto default_language_code = GetLocaleInfoString(
LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, force_defaults);
auto locale_language_code = LanguageCode(locale);
if (base::EqualsCaseInsensitiveASCII(locale_language_code,
default_language_code)) {
return LOCALE_USER_DEFAULT;
}
return CallLocaleNameToLCID(locale);
}
} // namespace
SandboxSupportImpl::SandboxSupportImpl() = default;
SandboxSupportImpl::~SandboxSupportImpl() = default;
void SandboxSupportImpl::BindReceiver(
mojo::PendingReceiver<mojom::SandboxSupport> receiver) {
receivers_.Add(this, std::move(receiver));
}
void SandboxSupportImpl::LcidAndFirstDayOfWeek(
const std::u16string& locale,
const std::u16string& default_language,
bool force_defaults,
LcidAndFirstDayOfWeekCallback callback) {
if (locale.size() > LOCALE_NAME_MAX_LENGTH ||
default_language.size() > LOCALE_NAME_MAX_LENGTH) {
receivers_.ReportBadMessage("Locale larger than LOCALE_NAME_MAX_LENGTH.");
return;
}
LCID lcid = LCIDFromLocale(locale, force_defaults);
if (!lcid) {
lcid = LCIDFromLocale(default_language, force_defaults);
}
auto first_day =
GetLocaleInfoDWORD(lcid, LOCALE_IFIRSTDAYOFWEEK, force_defaults);
int first_day_of_week = ((first_day.has_value() ? *first_day : 0) + 1) % 7;
std::move(callback).Run(lcid, first_day_of_week);
}
// https://learn.microsoft.com/en-us/windows/win32/intl/locale-idigitsubstitution
constexpr inline DWORD kDigitSubstitution0to9 = 1;
// https://learn.microsoft.com/en-us/windows/win32/intl/locale-ineg-constants
constexpr inline DWORD kNegNumberSignPrefix = 1;
void SandboxSupportImpl::DigitsAndSigns(uint32_t lcid,
bool force_defaults,
DigitsAndSignsCallback callback) {
DWORD digit_substitution =
GetLocaleInfoDWORD(lcid, LOCALE_IDIGITSUBSTITUTION, force_defaults)
.value_or(kDigitSubstitution0to9);
std::u16string digits;
if (digit_substitution != kDigitSubstitution0to9) {
digits = GetLocaleInfoString(lcid, LOCALE_SNATIVEDIGITS, force_defaults);
}
auto decimal = GetLocaleInfoString(lcid, LOCALE_SDECIMAL, force_defaults);
auto thousand = GetLocaleInfoString(lcid, LOCALE_STHOUSAND, force_defaults);
auto negative_sign =
GetLocaleInfoString(lcid, LOCALE_SNEGATIVESIGN, force_defaults);
DWORD negnumber = GetLocaleInfoDWORD(lcid, LOCALE_INEGNUMBER, force_defaults)
.value_or(kNegNumberSignPrefix);
std::move(callback).Run(digit_substitution, digits, decimal, thousand,
negative_sign, negnumber);
}
void SandboxSupportImpl::LocaleStrings(uint32_t lcid,
bool force_defaults,
LcTypeStrings collection,
LocaleStringsCallback callback) {
std::vector<std::u16string> result;
switch (collection) {
case LcTypeStrings::kMonths: {
static constexpr LCTYPE kTypes[12] = {
LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
};
result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, false);
break;
}
case LcTypeStrings::kShortMonths: {
static constexpr LCTYPE kTypes[12] = {
LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
};
result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, false);
break;
}
case LcTypeStrings::kShortWeekDays: {
static constexpr LCTYPE kTypes[7] = {
// Numbered 1 (Monday) - 7 (Sunday), so do 7, then 1-6
LOCALE_SSHORTESTDAYNAME7, LOCALE_SSHORTESTDAYNAME1,
LOCALE_SSHORTESTDAYNAME2, LOCALE_SSHORTESTDAYNAME3,
LOCALE_SSHORTESTDAYNAME4, LOCALE_SSHORTESTDAYNAME5,
LOCALE_SSHORTESTDAYNAME6};
result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, false);
break;
}
case LcTypeStrings::kAmPm: {
static constexpr LCTYPE kTypes[2] = {
LOCALE_S1159,
LOCALE_S2359,
};
result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, true);
break;
}
}
std::move(callback).Run(result);
}
void SandboxSupportImpl::LocaleString(uint32_t lcid,
bool force_defaults,
LcTypeString type,
LocaleStringCallback callback) {
LCTYPE lctype;
switch (type) {
case LcTypeString::kShortDate:
lctype = LOCALE_SSHORTDATE;
break;
case LcTypeString::kYearMonth:
lctype = LOCALE_SYEARMONTH;
break;
case LcTypeString::kTimeFormat:
lctype = LOCALE_STIMEFORMAT;
break;
case LcTypeString::kShortTime:
lctype = LOCALE_SSHORTTIME;
break;
}
auto result = GetLocaleInfoString(lcid, lctype, force_defaults);
std::move(callback).Run(result);
}
} // namespace content