blob: 259ca65f76ab998f16a3d149541e6d6f517d1911 [file] [log] [blame]
Alex Gougha5a75192025-01-07 17:12:571// Copyright 2025 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <windows.h>
6
7#include <string>
8#include <string_view>
9
10#include "base/strings/string_util.h"
11#include "base/strings/string_util_win.h"
12#include "content/browser/sandbox_support_impl.h"
13
14namespace content {
15namespace {
16LCID CallLocaleNameToLCID(std::u16string_view locale) {
17 CHECK(locale.size() < LOCALE_NAME_MAX_LENGTH);
18 return ::LocaleNameToLCID(base::as_wcstr(locale), 0);
19}
20
21std::u16string GetLocaleInfoString(LCID lcid,
22 LCTYPE type,
23 bool force_defaults) {
24 if (force_defaults) {
25 type = type | LOCALE_NOUSEROVERRIDE;
26 }
27 int size_with_nul = ::GetLocaleInfo(lcid, type, 0, 0);
28 if (size_with_nul <= 0) {
29 return std::u16string();
30 }
31 std::u16string buffer;
32 // basic_string guarantees that `buffer` can be indexed from
33 // [0, size], with the requirement that buffer[size] is only set
34 // to NUL.
35 buffer.resize(size_with_nul - 1);
36 ::GetLocaleInfo(lcid, type, base::as_writable_wcstr(buffer.data()),
37 size_with_nul);
38 return buffer;
39}
40
41std::vector<std::u16string> GetLocaleInfoStrings(LCID lcid,
42 base::span<const LCTYPE> types,
43 bool force_defaults,
44 bool allow_empty) {
45 std::vector<std::u16string> strings;
46 for (const auto& type : types) {
47 auto str = GetLocaleInfoString(lcid, type, force_defaults);
48 if (str.empty() && !allow_empty) {
49 return {};
50 }
51 strings.push_back(std::move(str));
52 }
53 return strings;
54}
55
56std::optional<DWORD> GetLocaleInfoDWORD(LCID lcid,
57 LCTYPE type,
58 bool force_defaults) {
59 DWORD result = 0;
60 if (force_defaults) {
61 type = type | LOCALE_NOUSEROVERRIDE;
62 }
63 if (::GetLocaleInfo(lcid, type | LOCALE_RETURN_NUMBER,
64 reinterpret_cast<LPWSTR>(&result),
65 sizeof(DWORD) / sizeof(TCHAR)) > 0) {
66 return result;
67 }
68 return std::nullopt;
69}
70
71std::u16string_view LanguageCode(const std::u16string_view locale) {
72 size_t dash_pos = locale.find('-');
73 if (dash_pos == std::u16string::npos) {
74 return locale;
75 }
76 return locale.substr(0, dash_pos);
77}
78
79LCID LCIDFromLocale(const std::u16string& locale, bool force_defaults) {
80 auto default_language_code = GetLocaleInfoString(
81 LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, force_defaults);
82 auto locale_language_code = LanguageCode(locale);
83 if (base::EqualsCaseInsensitiveASCII(locale_language_code,
84 default_language_code)) {
85 return LOCALE_USER_DEFAULT;
86 }
87 return CallLocaleNameToLCID(locale);
88}
89
90} // namespace
91
92SandboxSupportImpl::SandboxSupportImpl() = default;
93SandboxSupportImpl::~SandboxSupportImpl() = default;
94
95void SandboxSupportImpl::BindReceiver(
96 mojo::PendingReceiver<mojom::SandboxSupport> receiver) {
97 receivers_.Add(this, std::move(receiver));
98}
99
100void SandboxSupportImpl::LcidAndFirstDayOfWeek(
101 const std::u16string& locale,
102 const std::u16string& default_language,
103 bool force_defaults,
104 LcidAndFirstDayOfWeekCallback callback) {
105 if (locale.size() > LOCALE_NAME_MAX_LENGTH ||
106 default_language.size() > LOCALE_NAME_MAX_LENGTH) {
107 receivers_.ReportBadMessage("Locale larger than LOCALE_NAME_MAX_LENGTH.");
108 return;
109 }
110 LCID lcid = LCIDFromLocale(locale, force_defaults);
111 if (!lcid) {
112 lcid = LCIDFromLocale(default_language, force_defaults);
113 }
114 auto first_day =
115 GetLocaleInfoDWORD(lcid, LOCALE_IFIRSTDAYOFWEEK, force_defaults);
116 int first_day_of_week = ((first_day.has_value() ? *first_day : 0) + 1) % 7;
117 std::move(callback).Run(lcid, first_day_of_week);
118}
119
120// https://learn.microsoft.com/en-us/windows/win32/intl/locale-idigitsubstitution
121constexpr inline DWORD kDigitSubstitution0to9 = 1;
122// https://learn.microsoft.com/en-us/windows/win32/intl/locale-ineg-constants
123constexpr inline DWORD kNegNumberSignPrefix = 1;
124
125void SandboxSupportImpl::DigitsAndSigns(uint32_t lcid,
126 bool force_defaults,
127 DigitsAndSignsCallback callback) {
128 DWORD digit_substitution =
129 GetLocaleInfoDWORD(lcid, LOCALE_IDIGITSUBSTITUTION, force_defaults)
130 .value_or(kDigitSubstitution0to9);
131 std::u16string digits;
132 if (digit_substitution != kDigitSubstitution0to9) {
133 digits = GetLocaleInfoString(lcid, LOCALE_SNATIVEDIGITS, force_defaults);
134 }
135 auto decimal = GetLocaleInfoString(lcid, LOCALE_SDECIMAL, force_defaults);
136 auto thousand = GetLocaleInfoString(lcid, LOCALE_STHOUSAND, force_defaults);
137 auto negative_sign =
138 GetLocaleInfoString(lcid, LOCALE_SNEGATIVESIGN, force_defaults);
139 DWORD negnumber = GetLocaleInfoDWORD(lcid, LOCALE_INEGNUMBER, force_defaults)
140 .value_or(kNegNumberSignPrefix);
141 std::move(callback).Run(digit_substitution, digits, decimal, thousand,
142 negative_sign, negnumber);
143}
144
145void SandboxSupportImpl::LocaleStrings(uint32_t lcid,
146 bool force_defaults,
147 LcTypeStrings collection,
148 LocaleStringsCallback callback) {
149 std::vector<std::u16string> result;
150 switch (collection) {
151 case LcTypeStrings::kMonths: {
152 static constexpr LCTYPE kTypes[12] = {
153 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
154 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
155 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
156 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
157 };
158 result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, false);
159 break;
160 }
161 case LcTypeStrings::kShortMonths: {
162 static constexpr LCTYPE kTypes[12] = {
163 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
164 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
165 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
166 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
167 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
168 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
169 };
170 result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, false);
171 break;
172 }
173 case LcTypeStrings::kShortWeekDays: {
174 static constexpr LCTYPE kTypes[7] = {
175 // Numbered 1 (Monday) - 7 (Sunday), so do 7, then 1-6
176 LOCALE_SSHORTESTDAYNAME7, LOCALE_SSHORTESTDAYNAME1,
177 LOCALE_SSHORTESTDAYNAME2, LOCALE_SSHORTESTDAYNAME3,
178 LOCALE_SSHORTESTDAYNAME4, LOCALE_SSHORTESTDAYNAME5,
179 LOCALE_SSHORTESTDAYNAME6};
180 result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, false);
181 break;
182 }
183 case LcTypeStrings::kAmPm: {
184 static constexpr LCTYPE kTypes[2] = {
185 LOCALE_S1159,
186 LOCALE_S2359,
187 };
188 result = GetLocaleInfoStrings(lcid, kTypes, force_defaults, true);
189 break;
190 }
191 }
192
193 std::move(callback).Run(result);
194}
195
196void SandboxSupportImpl::LocaleString(uint32_t lcid,
197 bool force_defaults,
198 LcTypeString type,
199 LocaleStringCallback callback) {
200 LCTYPE lctype;
201 switch (type) {
202 case LcTypeString::kShortDate:
203 lctype = LOCALE_SSHORTDATE;
204 break;
205 case LcTypeString::kYearMonth:
206 lctype = LOCALE_SYEARMONTH;
207 break;
208 case LcTypeString::kTimeFormat:
209 lctype = LOCALE_STIMEFORMAT;
210 break;
211 case LcTypeString::kShortTime:
212 lctype = LOCALE_SSHORTTIME;
213 break;
214 }
215 auto result = GetLocaleInfoString(lcid, lctype, force_defaults);
216 std::move(callback).Run(result);
217}
218
219} // namespace content