xref: /aosp_15_r20/external/cronet/base/win/i18n.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2010 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 "base/win/i18n.h"
6 
7 #include <windows.h>
8 
9 #include <ostream>
10 #include <string_view>
11 
12 #include "base/check_op.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/string_util.h"
15 
16 namespace {
17 
18 using GetPreferredUILanguages_Fn = decltype(::GetSystemPreferredUILanguages)*;
19 
20 constexpr std::wstring_view kNullTerminator{L"\0", 1};
21 
GetPreferredUILanguageList(GetPreferredUILanguages_Fn function,ULONG flags,std::vector<std::wstring> * languages)22 bool GetPreferredUILanguageList(GetPreferredUILanguages_Fn function,
23                                 ULONG flags,
24                                 std::vector<std::wstring>* languages) {
25   DCHECK_EQ((flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME)), 0U);
26   const ULONG call_flags = flags | MUI_LANGUAGE_NAME;
27   ULONG language_count = 0;
28   ULONG buffer_length = 0;
29   if (!function(call_flags, &language_count, nullptr, &buffer_length) ||
30       !buffer_length) {
31     DPCHECK(!buffer_length) << "Failed getting size of preferred UI languages.";
32     return false;
33   }
34 
35   std::wstring buffer(buffer_length, '\0');
36   if (!function(call_flags, &language_count, std::data(buffer),
37                 &buffer_length) ||
38       !language_count) {
39     DPCHECK(!language_count) << "Failed getting preferred UI languages.";
40     return false;
41   }
42 
43   // The buffer has been populated with a series of strings separated by
44   // terminators, which ends with a single empty string (two terminators in a
45   // row). Chop off the last of those two terminators so that |buffer| is a
46   // basic_string that contains the terminator ending the last string but not
47   // the terminator denoting an empty string.
48   buffer.resize(buffer_length - 1);
49 
50   // Split string on NUL characters.
51   ULONG languages_added = 0;
52   for (auto token :
53        base::SplitStringPiece(buffer, kNullTerminator, base::KEEP_WHITESPACE,
54                               base::SPLIT_WANT_NONEMPTY)) {
55     languages->emplace_back(token);
56     ++languages_added;
57   }
58   DCHECK_EQ(languages_added, language_count);
59   return true;
60 }
61 
62 }  // namespace
63 
64 namespace base {
65 namespace win {
66 namespace i18n {
67 
GetUserPreferredUILanguageList(std::vector<std::wstring> * languages)68 bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) {
69   DCHECK(languages);
70   return GetPreferredUILanguageList(::GetUserPreferredUILanguages, 0,
71                                     languages);
72 }
73 
GetThreadPreferredUILanguageList(std::vector<std::wstring> * languages)74 bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) {
75   DCHECK(languages);
76   return GetPreferredUILanguageList(
77       ::GetThreadPreferredUILanguages,
78       MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK, languages);
79 }
80 
81 }  // namespace i18n
82 }  // namespace win
83 }  // namespace base
84